问题
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());
}
Should print
0
1
Is something like this possible?
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; \
}
回答1:
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.
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;
}
In above code, LSEG expands to something like section(".rodata.line01234") generated from __LINE__
information.
Here's an expalanation of how this works:
- 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.
Hope this helps.
回答2:
Why must this be a macro? Anyway, you can just wrap a function with a static counter in a macro:
int count_calls() {
static count = 0;
return count++;
}
#define MACRO() count_calls()
回答3:
What's wrong with
// global variable
std::vector<bool> calls_hit;
inline void a_function_since_this_is_not_C_after_all()
{
static unsigned int hits = 0;
const int counter = hits++;
calls_hit.resize(std::max(calls_hit.size(), counter));
calls_hit[counter] = true;
}
来源:https://stackoverflow.com/questions/4033011/cpp-macro-counter-that-gives-number-of-instantiations-calls