tags:

views:

893

answers:

5

The title pretty much says it all.

The __COUNTER__ symbol is provided by VC++ and GCC, and gives an increasing non-negative integral value each time it is used.

I'm interested to learn whether anyone's ever used it, and whether it's something that would be worth standardising?

+4  A: 

I've never used it for anything but a DEBUG macro. It's convenient to be able to say

#define WAYPOINT \
    do { if(dbg) printf("At marker: %d\n", __COUNTER__); } while(0);
Charlie Martin
Interesting. But how is this as good as / better than using __FILE__. After all, that will tell you exactly where the waypoint is, rather than perhaps having to search the file for WAYPOINT instances? Am I missing something ;-)
dcw
Well, you might be missing me saying "this is *all* I've ever found it useful for." Which isn't very.
Charlie Martin
Ok. Thanks for clarifying.btw, you might want to look at the code. Not sure the format specifier type is what you intended. ;-)
dcw
Me again: kudos on the do {} while(0), btw. :-)
dcw
What, %d? It was always %d. Nothing else. Never changed. Yeah, that's the ticket.
Charlie Martin
strager
Charlie Martin
strager
Right. Now think about this inside an if. See, eg, here: http://mail.nl.linux.org/kernelnewbies/2001-09/msg00230.html There's a reason this is the canonical way of doing a complex #define
Charlie Martin
strager
There's an extra ';' at the end of your #define...
johnny
No there isn't. It's there on purpose. If someone writes WAYPOINT; the extra ; is a no-op, silently optimized out. Do it the other way and it can become a syntax error somewhere south of the macro, with the cause hidden in the macro body.
Charlie Martin
+4  A: 

I've used it in a compile-time assertion macro to have the macro create a name for a typedef that will be unique. See

if you want the gory details.

Michael Burr
Why do you want unique name for each of typedefs? They will be either defined eqiuvalently or compilation will fail.
n0rd
@nOrd - hmm - either it's over-engineered or there's a reason that's escaping me... but, I probably won't revisit it, since the C_ASSERT stuff seems to be working just fine for me.
Michael Burr
+2  A: 

If I'm understanding the functionality correctly, I wished I had that functionality when I was working in Perl, adding an Event Logging function into an existing GUI. I wanted to ensure that the needed hand testing (sigh) gave us complete coverage, so I logged every test point to a file, and logging a __counter__ value made it easy to see what was missing in the coverage. As it was, I hand coded the equivalent.

Leonard
Sounds interesting. How did you "hand code" the equiv.?
dcw
As I reread my own post, I didn't really hand-code the equivalent. I just put counters in by hand. (hard coded all the numbers throughout each file.) That's why I wish I'd had the functionality.
Leonard
+1  A: 

Its used in the xCover code coverage libray, to mark the lines that execution passes through, to find ones that are not covered.

JamieH
Interesting I'll cehck it out. Thanks
dcw
+1  A: 

__COUNTER__ is useful anywhere you need a unique name. I have used it extensively for RAII style locks and stacks. Consider:

struct TLock
{
  void Lock();
  void Unlock();
}
g_Lock1, g_Lock2;

struct TLockUse
{
  TLockUse( TLock &lock ):m_Lock(lock){ m_Lock.Lock(); }
  ~TLockUse(){ m_Lock.Unlock(); }

  TLock &m_Lock;
};

void DoSomething()
{
  TLockUse lock_use1( g_Lock1 );
  TLockUse lock_use2( g_Lock2 );
  // ...
}

It gets tedious to name the lock uses, and can even become a source of errors if they're not all declared at the top of a block. How do you know if you're on lock_use4 or lock_use11? It's also needless pollution of the namespace - I never need to refer to the lock use objects by name. So I use __COUNTER__:

#define CONCAT_IMPL( x, y ) x##y
#define MACRO_CONCAT( x, y ) CONCAT_IMPL( x, y )
#define USE_LOCK( lock ) TLockUse MACRO_CONCAT( LockUse, __COUNTER__ )( lock )

void DoSomething2()
{
  USE_LOCK( g_Lock1 );
  USE_LOCK( g_Lock2 );
  // ...
}

But don't get hung up on the fact I called the objects locks - any function(s) that need to get called in matching pairs fit this pattern. You might even have multiple uses on the same "lock" in a given block.

Chris