Preprocessor facility __COUNTER__ in Visual C++

Viewed 2624

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) \
        if(g_testThrowExceptionIndex == n)\
        {\
          g_testThrowExceptionIndex++;\
          throw g_testThrowExceptionIndex;\
        }\

Without the ability to generate the sequence number at compile time, I have to write the Macro like this:

TEST_THROW_EXCEPTION(THROW_INDEX_1)
......
TEST_THROW_EXCEPTION(THROW_INDEX_N)

And in the header, defines:

#define THROW_INDEX_1 0
#define THROW_INDEX_2 1
......

The problem is, every time you add a try/catch block and you want to test, you have to create a new constant through #define and put that number into the Macro. Worse, what if you remove some of the try/catch blocks from the code? You have to update your #define list too...

==============

Solution: Thanks for Suma's idea, I ended up with something like this:

#if defined(_DEBUG)  && defined(_EXCEPTION_TEST)
  extern int g_testThrowExceptionIndex;
  struct GCounter
  {
    static int counter; // used static to guarantee compile time initialization
    static int NewValue() {return counter++;}
  };
  #define TEST_THROW_EXCEPTION \
      static int myConst = GCounter::NewValue();\
      if(g_testThrowExceptionIndex == myConst)\
      {\
        g_testThrowExceptionIndex++;\
        throw 0;\
      }
#else
  #define TEST_THROW_EXCEPTION 
#endif

In main.cpp:

#if defined(_DEBUG) && defined(_EXCEPTION_TEST)
  int g_testThrowExceptionIndex= 0;
  int GCounter::counter= 0;
#endif

Then you can put "TEST_THROW_EXCEPTION" in any of your try/catch block you want to test out.

2 Answers
Related