CPP Macro: Counter that gives number of instantiations/calls

拟墨画扇 提交于 2019-12-24 01:42:11

问题


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:

  1. 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.
  2. LSEG macro expands to section specifier with a line number (ex: section(".rodata.line01234")).
  3. 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.
  4. 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!