C语言宏处理器用户指导

摘自 C Preprocessor User Guide

宏替换原则:

Macro arguments are completely macro-expanded before they are substituted into a macro body, unless they are stringified or pasted with other tokens. After substitution, the entire macro body, including the substituted arguments, is scanned again for macros to be expanded. The result is that the arguments are scanned twice to expand macro calls in them.  

宏参数会在替换到宏定义体内之前,会进行完全的宏展开,除非他们是字符串化 # 或连接化操作 ## 的一部分。在替换后,整个宏定义体,包括被替换的参数,被再次被扫描,进行宏展开。 结果是参数被扫描了2次,进行宏调用展开。

Most of the time, this has no effect. If the argument contained any macro calls, they are expanded during the first scan. The result therefore contains no macro calls, so the second scan does not change it. If the argument were substituted as given, with no prescan, the single remaining scan would find the same macro calls and produce the same results.

通常情况下这是没有效果的(宏调用的二次宏展开),因为如果参数包含了任何宏调用,那么他们会在第一次扫描时被展开,结果常常是不再包含宏调用了,所以第二次扫描时,并没有什么改变发生。假设没有预扫描的话,那么被替换的宏参数,会在扫描后出现了同样的宏调用,这会产生相同的结果。 


即宏替换原则:

当一个宏参数被放进宏体时,通常(注意,有例外)这个宏参数会首先被全部展开。当展开后的宏参数被放进宏体时,预处理器对新展开的宏体进行第二次扫描,并继续展开 。

#define PARAM( x )       x
#define ADDPARAM( x )   INT_##x
PARAM( ADDPARAM( 1 ) );
因为ADDPARAM( 1 ) 是作为PARAM的宏参数,所以先将ADDPARAM( 1 )展开为INT_1,然后再将INT_1放进PARAM。

例外情况是,如果PARAM宏里对宏参数使用了#或##,那么宏参数不会被展开:
#define PARAM( x ) #x
#define ADDPARAM( x ) INT_##x
PARAM( ADDPARAM( 1 ) ); 将被展开为"ADDPARAM( 1 )"。



了解#和##的意义:

#define f(a,b) a##b
#define g(a)   #a
#define h(a) g(a)

# 将右边的参数做整体的字符串替换。#define g(a) #a   则g(hello world)  即  “hello world”      g(sleep(1))    即  “sleep(1)”
对于#的参数,即便是另一个宏,也不展开,仍然作为字符串字面信息输出。

所以,g(f(1,2))  “f(1,2)”    对于h(f(1,2)),由于h(a)是非#或##的普通宏,需要先宏展开其参数a,即展开f(1,2)为12,则h(a) 宏替换为h(12),进而宏替换为g(12), 进而宏替换为“12”

 即#表示将其后的内容转换为字符串,而##表示将它前后两个TOKEN连接为一个。

还有一点需要注意的是(特别是遇到分析复杂的宏定义时):

1.宏定义的最外层括号中的逗号为实参分隔符,内层的不分隔该层实参;
2.带有预处理指令#或##的形参,不参与宏替换或宏展开




你可能感兴趣的:(C++)