代码之家  ›  专栏  ›  技术社区  ›  Manuel

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

  •  2
  • Manuel  · 技术社区  · 15 年前

    我想要一个 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 回复  |  直到 10 年前
        1
  •  2
  •   Taisuke Yamada    14 年前

    我碰巧有一个解决方案类似于 __COUNTER__ ,但不限于单个计数器-可以根据需要定义多个计数器。

    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__ 信息。

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

    1. 每当您使用MY_COUNTER宏时,它将被替换为两个代码片段:1)推动 __生产线__ LSEG宏指定的内存段值,以及2)调用getpos的代码( )函数,返回写入给定行的调用数。
    2. LSEG宏扩展为带有行号的节说明符(例如:节(“.rodata.line01234”)。
    3. 通过指定链接器以按字母顺序(-Wl,--sort segment=name with GNU ld)对段进行排序,可以确保 __生产线__ 值按使用顺序排列。
    4. 在运行时,getpos( __生产线__ )函数扫描内存段,并返回写入给定行的调用数。

        2
  •  5
  •   Konrad Rudolph    15 年前

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

    int count_calls() {
        static count = 0;
        return count++;
    }
    
    #define MACRO() count_calls()
    
        3
  •  1
  •   sbi    15 年前

    怎么了

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