visualc++中的预处理器设施__COUNTER__
Preprocessor facility __COUNTER__ in Visual C++
我需要在编译时在整个代码中生成一系列连续的数字。我用如下方式尝试了"__COUNTER__":
void test1()
{
printf("test1(): Counter = %dn", __COUNTER__);
}
void test2()
{
printf("test2(): Counter = %dn", __COUNTER__);
}
int main()
{
test1();
test2();
}
结果如我所料是完美的:
test1(): Counter = 0
test2(): Counter = 1
然后我把"__COUNTER__"分散到不同的。cpp文件中:
In Foo.cpp:
Foo::Foo()
{
printf("Foo::Foo() with counter = %dn", __COUNTER__);
}
In Bar.cpp:
Bar::Bar()
{
printf("Bar::Bar() with counter = %dn", __COUNTER__);
}
In Main.cpp:
int main()
{
Foo foo;
Bar bar;
}
结果是:
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__)
//My logic is here...
}
catch(...)
{
//Log or notify...
}
宏应该是这样的:
#define TEST_THROW_EXCEPTION(n)
if(g_testThrowExceptionIndex == n)
{
g_testThrowExceptionIndex++;
throw g_testThrowExceptionIndex;
}
由于无法在编译时生成序列号,我必须这样编写宏:
TEST_THROW_EXCEPTION(THROW_INDEX_1)
......
TEST_THROW_EXCEPTION(THROW_INDEX_N)
在header中定义:
#define THROW_INDEX_1 0
#define THROW_INDEX_2 1
......
问题是,每次你添加一个try/catch块,你想测试,你必须通过#define创建一个新的常量,并把这个数字到宏。更糟糕的是,如果从代码中删除一些try/catch块会怎么样?你也必须更新你的#define list…
==============
解决方案:感谢Suma的想法,我最终得到了这样的东西:
#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
在main.cpp: #if defined(_DEBUG) && defined(_EXCEPTION_TEST)
int g_testThrowExceptionIndex= 0;
int GCounter::counter= 0;
#endif
然后你可以把"TEST_THROW_EXCEPTION"放在任何你想测试的try/catch块中
使用预处理器无法做到这一点,因为每个编译单元都是单独预处理的。为此需要一个运行时解决方案。你可以创建一个全局单例,每个需要唯一标识符的地方都可以使用这个单例定义一个静态int。
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();
}
注意:在多个编译单元中,这些静态值(id)的初始化顺序没有定义。您可以确定它们总是唯一的,但您不能依赖它们具有某些特定的值或顺序。因此,在将它们保存到文件中时要小心-您应该将它们转换为一些中立的表示。
看到您正在使用MSVC,您总是可以添加一个预构建步骤来解析文件并将__COUNTER__
扩展为超全局值而不是单位全局值。当然,困难的部分是管理文件,以免引起问题……
- CMake 用于设定C++标准的设施 "at least C++NN"
- 添加调试设施以提升变体访问者
- 错误:在 C++ 中从 'Counter' 转换为非标量类型'CountDn'
- 链接器错误:"cannot move location counter backwards (from 200009f8 to 20000800)"
- 有没有办法在C++中制作无锁"counter"随机访问迭代器?
- 将标准引入标准::web_view设施有什么好处?
- 看起来如此主要的错误.cpp:(.text.startup+0xd6):未定义对"vtable for Counter"的引用?
- 我可以打电话给<algorithm>空旷的设施吗?
- 分配但不使用分配器的标准图书馆设施
- C++是否有强有力的保证交换设施
- 了解 <system_error> C++11 中的设施
- 使用Boost随机基础设施,但如何轻松更换组件(例如底层生成器)
- 为什么 C++11 标准中的 INVOKE 设施是指数据成员?
- C库设施标头的命名空间注入不一致
- 类标头和在我的类.cpp文件中使用构造函数:"error: class 'Test' does not have any field named 'counter'"
- c代码第43行中“counter::counter”的使用无效
- map<int,int> 计数器; counter[nums[i]]++;
- C++中的文档字符串设施
- JUCE原子设施的记忆顺序是什么?
- 在使用Nifty Counter C++Idiom时,必须调用构造函数两次