C++ CPP宏:给出实例化/调用次数的计数器

C++ CPP宏:给出实例化/调用次数的计数器,c++,c-preprocessor,C++,C Preprocessor,我想要一个C预处理器宏,它知道到目前为止该宏的实例化/宏调用的数量。 例如: 应该打印 0 1 这样的事情可能吗 请注意,不足以将其转发给下面建议的功能。 它应在以下背景下发挥作用: // global variable std::vector<bool> calls_hit; #define OTHER_MACRO() \ { \ const int counter = MACRO(); \ calls_hit.resize(std::max(calls_hit

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

应该打印

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; \
}
//全局变量
std::向量调用\u hit;
#定义其他_宏()\
{ \
常量int计数器=宏()\
调用_hit.resize(std::max(调用_hit.size(),计数器))\
调用\u hit[计数器]=真\
}

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

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

#define MACRO() count_calls()
你怎么了

// 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;
}
//全局变量
std::向量调用\u hit;
内联无效函数,因为此函数不是
{
静态无符号整数命中=0;
常量int计数器=命中++;
调用_hit.resize(std::max(调用_hit.size(),计数器));
调用\u hit[计数器]=真;
}

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

这一个使用特定于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扩展到类似于从
\uuuuuuuuuuuuuuuuuuuu
信息生成的部分(“.rodata.line01234”)

以下是对其工作原理的解释:

  • 每当您使用MY_COUNTER宏时,它都会被两个代码片段所取代:1)将
    \uuuuuuuuuuuuuuuuuuuuu值推送到LSEG宏指定的内存段的代码,以及2)调用getpos(
    \uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu行
    )函数的代码,该函数返回写入给定行的调用次数
  • LSEG宏扩展为带有行号的节说明符(例如:节(“.rodata.line01234”))
  • 通过指定按字母顺序对段进行排序的链接器(-Wl,--sort segment=name with GNU ld),可以确保所有附加的
    \uuuu LINE\uuu
    值都是按使用顺序排列的
  • 在运行时,getpos(
    \uuuuuuuu LINE\uuuuu
    )函数扫描内存段,并返回写入给定行的调用数

  • 希望这能有所帮助。

    @Andy:那么当然,计数也会增加。不,这不起作用。我想知道编译时的调用数。@Manuel:如果你想知道编译时的调用数,你必须使用类似于
    \uuuuu COUNTER\uuuu
    的宏来包装对目标函数的调用,但是,这意味着你不能使用
    \uuu COUNTER\uuuu
    来处理任何其他事情…@Manuel:不能使用宏。模板元编程可能会有所帮助,但您需要提供更多细节。特别是,我的解决方案仍然适用于您在问题中发布的新代码;没有编译时间知识。删除了<代码> C++ >代码>标签,因为这似乎不是C++。把<代码> C++ > /CODE>标签重新加入,因为现在使用的是代码> STD::vector < /代码>。代码>
    LSEG的定义来自哪里?快速的谷歌搜索什么也没发现。我省略了LSEG的定义,因为该定义本身是一个复杂的代码来解释。我目前在编辑时遇到了一些问题,比如定义STR(s)#s#定义STR(s)STR(s)#定义EVAL(func,…)func(VA#ARGS)#定义LSEG(n)部分(STR(.rodata.line##n))#定义LSEG EVAL(LSEG,ALIGN#数字(line))而ALIGN_DIGIT的定义太长,无法包含在这里,因为我通过定义#define ALIGN_DIGIT_1 00001#define ALIGN_DIGIT_2 00002……将其拼凑起来#定义ALIGN_DIGIT_65536 65536这是我找到的唯一方法,因为GNU ld只按非数字字典顺序对节进行排序。注意:我只是为了好玩才这么做的。像这样的宏不应该出现在现实世界的代码中。。。
    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;
    }