CPP宏:提供实例化/调用次数的计数器

时间:2010-10-27 12:13:23

标签: c++ c-preprocessor

我希望有一个 C 预处理器宏,它知道到目前为止该宏的实例化/宏调用的数量。 例如:

int main() {
  printf("%d\n", MACRO());
  printf("%d\n", MACRO());
}

应打印

0
1

这样的事情可能吗?

请注意,足以将其转发给下面建议的功能。 它应该在以下环境中起作用:

// 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; \
}

3 个答案:

答案 0 :(得分:5)

为什么这必须是一个宏?无论如何,您可以在宏中使用静态计数器包装函数:

int count_calls() {
    static count = 0;
    return count++;
}

#define MACRO() count_calls()

答案 1 :(得分:2)

我碰巧有一个与__COUNTER__类似(使用中)的解决方案,但不仅限于单个计数器 - 您可以根据需要定义许多计数器。

这个使用gcc特有的功能,但应该能够在其他工具链中做类似的事情。

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扩展为类似于__LINE__信息生成的section(“。rodata.line01234”)。

以下是对其工作原理的阐述:

  1. 无论何时使用MY_COUNTER宏,它都会被2个代码片段替换:1)将__LINE__值推送到LSEG宏指定的内存段的代码,以及2)调用getpos(__LINE__)的代码function,返回写入给定行的调用数。
  2. LSEG宏使用行号扩展为section说明符(例如:section(“。rodata.line01234”))。
  3. 通过指定链接器按字母顺序对段进行排序(-Wl, - sort-segment = name with GNU ld),可以确保所有附加的__LINE__值都按照它们的使用顺序排列。
  4. 在运行时,getpos(__LINE__)函数扫描内存段,并返回写入给定行的调用数。
  5. 希望这有帮助。

答案 2 :(得分:1)

有什么问题
// 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;
}