因为C的预处理器对于# operator的处理与普通的宏是不同的,假设有
#define STR abcdefg
#define mkstr(x) #x
#define showstr(x) mkstr(x)
那么对于mkstr(STR)和showstr(STR),预处理器的观点是不一样的:
mkstr宏的参数x在宏的替换列表当中直接跟在#的后面这时候预处理器会把它替换成为根
实参的spelling替换得来的字符量。所以mkstr(STR)会被替换成"STR"。
这个C标准规定如下:
[6.10.3.2.2]
If, in the replacement list, a parameter is immediately preceded by a #
preprocessing token, both are replaced by a single character string literal
preprocessing token that contains the spelling of the preprocessing token
sequence for the corresponding argument.
而showstr的参数x在替列表当中并不是直接根在#后面的,所以会执行标准的宏参数替换
。即从内到外的完全的宏替换,即把所有的实参全部展开,再执行当前的宏替换。因此
showstr的参数STR先被完全展开成abcdefg,然后执行showstr的展开,变成
mkstr(abcdefg),进而变成"abcdefg"。
这一段标准条文如下:
[6.10.3.1.1]
After the arguments for the invocation of a function-like macro have been
identified, argument substitution takes place. A parameter in the
replacement list, unless preceded by a # or ## preprocessing token or
followed by a ## preprocessing token (see below), is replaced by the
corresponding argument after all macros contained therein have been
expanded. Before being substituted, each argument’s preprocessing tokens
are completely macro replaced as if they formed the rest of the
preprocessing file; no other preprocessing tokens are available.
这样,前面的帖子给出的PRINT_MACRO的定义就很容易理解了。第一层展开PRINT_MACRO的时候,要先把参数arg对应的实参完全展开,之后经过__MACRO_S的处理变成文字量,经printf打印出来,获得的就是完整的宏展开之后的字符串了。