Visual C ++中的预处理器__COUNTER__ [英] Preprocessor facility __COUNTER__ in Visual C++

查看:147
本文介绍了Visual C ++中的预处理器__COUNTER__的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要在编译时在我的代码中生成一系列序列号。我以这样的方式尝试了__COUNTER__:

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

结果是完美的,如我所料:

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

然后我在不同的.cpp文件中传播__COUNTER__:

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

在Main.cpp中:
int main()
{
Foo foo;
吧台吧
}

结果是:

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

它看起来__COUNTER__作为每个编译单元变量提供。



我想要的是一个在整个代码中有效的全局计数器。



这是用于在调试生成中测试,这个目标:



想象一下,我在整个代码中都有try / catch块(一个子系统或多个.cpp文件中的一个模块)。在运行时程序运行在一个循环中,在每个循环内,所有的try块将按顺序执行(顺序无关紧要),我想测试代码如何对每个try / catch的异常做出反应,逐个。例如,第一次在循环中,#1 try / catch块抛出异常;第二次在循环中,#2 try / catch块引发异常等等。



我计划有一个全局计数器,如下:

  int g_testThrowExceptionIndex = 0; 

在每个try / catch中:

  try 
{
TEST_THROW_EXCEPTION(__ COUNTER__)
//我的逻辑是...
}
catch )
{
//记录或通知...
}

并且宏将是这样的:

  #define TEST_THROW_EXCEPTION(n)\ 
if(g_testThrowExceptionIndex == n)\
{\
g_testThrowExceptionIndex ++; \
throw g_testThrowExceptionIndex; \
} \
pre>

无法在编译时生成序列号,我必须这样编写宏:

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

在标题中定义:

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

问题是,你添加一个try / catch块,你想测试,你必须通过#define创建一个新的常量,并将该数字放入宏。更糟的是,如果你从代码中删除一些try / catch块呢?您还必须更新您的#define列表...



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



解决方案:
感谢Suma的想法,我最终得到了这样的:

 如果定义(_DEBUG)&& defined(_EXCEPTION_TEST)
extern int g_testThrowExceptionIndex;
struct GCounter
{
static int counter; //使用静态来保证编译时初始化
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
pre>

在main.cpp中:

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

然后你可以把TEST_THROW_EXCEPTION

$ p

解决方案

使用预处理器不能这样做,因为每个编译单元都是单独预处理的。需要运行时解决方案。您可以创建一个全局单例,每个需要唯一标识符的地方可以使用这个单例定义一个静态int。

  struct GCounter 
{
static int counter; //使用静态来保证编译时初始化
static int NewValue(){return counter ++;}
};

int GCounter :: counter = 0;

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

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

注意:在多个编译中初始化这些静态值单位未定义。你可以确定他们将永远是独一无二的,但你不能依靠他们有一些特定的值或顺序。因此,当例如将它们保存到文件中 - 您应该将它们转换为一个中性表示。


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.

解决方案

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.

这篇关于Visual C ++中的预处理器__COUNTER__的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆