CPP宏:提供实例化/调用次数的计数器 [英] CPP Macro: Counter that gives number of instantiations/calls
问题描述
我想拥有一个 C 预处理器宏,到目前为止,该宏知道该宏的实例化/宏调用的数量。
示例:
I want to have a C preprocessor macro that knows the number of instantiations/macro calls of this macro so far. Example:
int main() {
printf("%d\n", MACRO());
printf("%d\n", MACRO());
}
应打印
0
1
类似这样的可能?
请注意,将其转发给以下建议的功能还不够。
它应在以下环境下工作:
Note that it is not enough to forward this to a function as proposed below. It should work in the following context:
// global variable
std::vector<bool> calls_hit;
#define OTHER_MACRO() \
{ \
const int counter = MACRO(); \
calls_hit.resize(std::max(calls_hit.size(), counter)); \
calls_hit[counter] = true; \
}
推荐答案
我碰巧有一种与 __ COUNTER __
类似(使用)的解决方案,但不仅限于单个计数器-您可以根据需要定义多个计数器。
I happen to have a solution that is similar (in usage) to __COUNTER__
, but is not limited to single counter - you can define many counters as you like.
此功能使用了gcc特有的功能,但应该可以在其他工具链中执行类似的操作。
This one uses gcc-specific feature, but should be able to do similar in other toolchain.
static int getpos(int lineno); // forward declaration
#define MY_COUNTER ({ \
static const int mark __attribute__((LSEG,used)) = __LINE__; \
getpos(__LINE__); \
})
static int __attribute__((noinline)) getpos(int lineno) {
static const int mark __attribute__((LSEG,used)) = __LINE__;
const int *p = &mark;
int i;
for (i = 0; *p++ != lineno; i++);
return i;
}
在上面的代码中,LSEG扩展为section(。rodata.line01234 )是根据 __ LINE __
信息生成的。
In above code, LSEG expands to something like section(".rodata.line01234") generated from __LINE__
information.
以下是其工作原理的说明:
Here's an expalanation of how this works:
- 每当您使用MY_COUNTER宏时,它将被2个代码片段代替:1)将
__ LINE __
值压入的代码LSEG宏指定的内存段,以及2)调用getpos(__ LINE __
)函数的代码,该函数返回写入给定行的调用数。 - LSEG宏扩展到具有行号的段说明符(例如:section(。rodata.line01234))。
- 通过指定链接器以字母顺序对段进行排序(-Wl, --sort-segment = name与GNU ld),可以确保所有附加的
__ LINE __
值均按使用顺序排列。 - 在运行时,getpos(
__ LINE __
)函数扫描内存段,并返回写到给定行的调用数。
- Whenever you use MY_COUNTER macro, it is replaced with 2 code fragments: 1) code that pushes
__LINE__
value to memory segment specified by LSEG macro, and 2) code that calls getpos(__LINE__
) function, which returns # of calls written up to given line. - LSEG macro expands to section specifier with a line number (ex: section(".rodata.line01234")).
- By specifying linker to sort segment alphabetically (-Wl,--sort-segment=name with GNU ld), you can be sure all appended
__LINE__
values are in order they were used. - At run-time, getpos(
__LINE__
) function scans through the memory segment, and returns # of calls written up to given line.
希望这会有所帮助。
这篇关于CPP宏:提供实例化/调用次数的计数器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!