VS2017中C++字符串化运算符#为何仅支持宏参数而非普通宏?
#不能直接作用于普通宏?以及无参数实现方案 这个问题戳中了C++预处理器宏的核心规则,我来给你掰扯清楚:
一、为什么#BAR会报错?
字符串化运算符#是宏定义体内的专用工具,它的唯一作用是把当前宏的形式参数转换成对应的字符串字面量。
比如你写的#define PRINT(FOO) cout << #FOO;是合法的,因为FOO是这个宏的形参,预处理器明确知道要把传入的实参(比如调用PRINT(hello)时的hello)转成"hello"。
但当你直接写cout << #BAR;时,预处理器会一脸懵:它现在不在任何宏的定义上下文里,找不到对应的宏形参,自然抛出C2162错误——它期望这里是一个宏的形式参数,而不是一个已经定义好的宏名。简单说,#只能和宏参数绑定使用,不能直接“套”在普通宏上。
二、无参数的实现方式
如果你不想通过传参的方式实现,有两种实用思路:
1. 直接定义无参宏输出字符串
如果只是想输出"BAR"这个固定字符串,直接写死就行:
#define PRINT_BAR cout << "BAR";
调用时直接写PRINT_BAR;,完全不需要参数。
2. 用中转宏间接处理(支持动态展开宏内容)
如果你的需求是把BAR的定义内容字符串化(比如BAR是blah,你想输出"blah"),可以用两层中转宏实现:
// 第一层:负责执行字符串化操作 #define STRINGIFY(x) #x // 第二层:先展开宏参数,再传给STRINGIFY #define EXPAND_THEN_STRINGIFY(x) STRINGIFY(x) #define BAR blah // 最终输出"blah" cout << EXPAND_THEN_STRINGIFY(BAR);
这里的逻辑是:预处理器会先处理EXPAND_THEN_STRINGIFY(BAR),把BAR展开成blah,再把blah传给STRINGIFY,最终得到"blah"。如果直接用STRINGIFY(BAR),得到的会是"BAR"(因为#会直接把参数名转成字符串,不会先展开宏内容)。
如果只是想得到宏名的字符串("BAR"),用一层STRINGIFY(BAR)就够了,这也算一种“无参数”的调用方式——你只需要把目标宏作为参数传给中转宏,不需要额外定义带参宏。
内容的提问来源于stack exchange,提问作者buttonsrtoys

