【问题标题】:One issue with c++ macro expandc++宏展开的一个问题
【发布时间】:2013-09-10 03:52:36
【问题描述】:

当我使用 g++ 编译 cpp 文件时,gcc 给出以下错误消息:

错误:粘贴“TBSYS_LOG_LEVEL_”和“-”没有给出有效的预处理令牌

然后查看源码,发现有三个宏定义:

  • fileA.h 中:
#define TBSYS_LOG_LEVEL_ERROR 0
#define TBSYS_LOG(level, _fmt_, args...) ((TBSYS_LOG_LEVEL_##level>TBSYS_LOGGER._level) ? (void)0 : TBSYS_LOG_BASE(level, "[%ld] " _fmt_, pthread_self(), ##args))
  • fileB.h 中:
#define ERROR -1

原来“ERROR”在宏“TBSYS_LOG”展开之前被展开为“-1”。

TBSYS_LOG_LEVEL_##level”展开后的结果是“TBSYS_LOG_LEVEL_-1”,最终导致报错。

但是,据我所知,在这种情况下宏不会展开。 (使用##时)

然后我写了另一个cpp文件来试试这个:

#define FOOBAR 100
#define TEST(PARAM) FOO##PARAM
#define BAR -1

int main(){
    cout<<TEST(BAR)<<endl; 
}

这样就可以通过编译了。输出为 100。 这些宏定义和前一个一样,但没有将“BAR”扩展为“-1”,不会产生错误信息。

有人知道为什么宏在前一种情况下会扩展吗?


更新:使用 TBSYS_LOG 的代码是:

TBSYS_LOG(ERROR, "expand data buffer failed, length: %d", bufsize);

【问题讨论】:

  • 您的真实代码可能通过宏具有额外的间接级别。正是在这个额外的级别上,ERROR 得到了扩展。例如,如果您使用#define TEST2(PARAM) TEST(PARAM) 并使用TEST2(BAR),您将看到这一点。展示你如何使用TBSYS_LOG 宏。

标签: c++ c macros


【解决方案1】:
#define FOOBAR 100
#define TEST(PARAM) FOO##PARAM
#define BAR -1

int main(){
    cout<<TEST(BAR)<<endl; 
}

##PARAM 表示符号本身。所以TEST(BAR)这里展开为FOO##BAR(不是结果,只是解释),就是FOOBAR#define FOOBAR 100就是100。

BAR 永远不会作为独立符号出现(由空格或其他分隔符分隔),因此不能替换为 -1。

【讨论】:

    【解决方案2】:

    FOO##PARAM 会在编译时展开,所以在你运行代码之前,宏的值已经固定,它是 FOOBAR,如果你 像这样添加一个新参数:

    #define FOOBAR 100
    #define TEST(PARAM) FOO##PARAM
    #define BAR -1
    #define GOOD 10
    
    int main(){
        cout<<TEST(GOOD)<<endl; 
    }
    

    编译器可能永远不会让它为你工作。

    【讨论】:

    • 这是因为“FOOGOOD”不存在。 TEST(GOOD) 扩展为“FOOGOOD”,这没关系。问题中的情况就像 TEST(GOOD) 扩展到“FOO10”。
    猜你喜欢
    • 2018-10-14
    • 2014-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-29
    • 2016-03-21
    • 1970-01-01
    相关资源
    最近更新 更多