Alex Rivera | Logout

Preprocessor facility __COUNTER__ in Visual C++

Asked 2011-08-04T19:41:08.147
9

I need to generate a series of sequential numbers throughout my code at compile time. I tried "__COUNTER__" in a way like this:

void test1()
{
  printf("test1(): Counter = %d\n", __COUNTER__);
}
void test2()
{
  printf("test2(): Counter = %d\n", __COUNTER__);
}
int main()
{
  test1();
  test2();
}

And the result was perfect as I expected:

test1(): Counter = 0
test2(): Counter = 1

Then I spread "__COUNTER__" out in different .cpp files:

In Foo.cpp:
Foo::Foo()
{
  printf("Foo::Foo() with counter = %d\n", __COUNTER__);
}
In Bar.cpp:
Bar::Bar()
{
  printf("Bar::Bar() with counter = %d\n", __COUNTER__);
}

In Main.cpp:
int main()
{
  Foo foo;
  Bar bar;
}

The result was:

Foo::Foo() with counter = 0
Bar::Bar() with counter = 0

It looks to me that "__COUNTER__" is provided as a per compile unit variable.

What I'd like to have is a global counter that's effective throughout the code.

This is used for testing in a debug build where I want to achieve this goal:

Imagine that I have try/catch blocks throughout the code (a subsystem or a module within multiple .cpp files). At run time the program is running in a loop, within each loop all the try blocks will be executed in orders (in which order doesn't matter), and I want to test how the code react to exception for each try/catch, one by one. For example, the first time in the loop, #1 try/catch block throws an exception; second time in the loop, #2 try/catch block throws an exception, etc etc.

I plan to have a global counter like this:

int g_testThrowExceptionIndex = 0;

In each try/catch:

try
{
  TEST_THROW_EXCEPTION(__COUNTER__)
  //My logic is here...
}
catch(...)
{
  //Log or notify...
}

And the Macro would be something like this:

#define TEST_THROW_EXCEPTION(n) \
  
Edit
Report

1 Answer

5

You cannot do this using preprocessor, as each compile unit is preprocessed separately. A run time solution is needed for this. You may create a global singleton and each place which requires a unique identifier can define a static int using this singleton.

struct GCounter
{
  static int counter; // used static to guarantee compile time initialization
  static int NewValue() {return counter++;}
};

int GCounter::counter = 0;

void Foo1()
{
  static int ID1 = GCounter::NewValue();
}

void Foo2()
{
  static int ID2 = GCounter::NewValue();
}

Note: the order of initialization of those static values (IDs) in multiple compilation units is not defined. You can be sure they will be always unique, but you cannot rely upon them having some particular values or ordering. Therefore be careful when e.g. saving them into a file - you should translate them to some neutral representation for that.

answered 2011-08-04T19:55:18.283

Your Answer