c语言宏
使用
c语言的宏是在预处理时候对字符进行简单替换。
优点:1.如果要改一个变量,只需要改宏就可以了,也就是只改一次;2.宏函数展开和普通函数一样,但是它没有普通函数调用的过程,不需要压栈出栈等操作,所以效率高。
缺点:增大了编译后可执行文件的大小
比如常见的
#define max(a,b) ((a)>(b)?(a):(b))
变量使用括号包围,否则这样调用时
max(8+3,6+1)
结果并不是我们想要的
即使使用括号包围了,宏依然是有陷阱的,比如这样调用
a = 3; max(a++, 8)
宏展开之后,成了这样:
((a++)>(8)?(a++):(8))
a++被执行了两次
再比如,在宏中调用了函数,那么,这个函数可能被执行了多次。
gdb调试
使用gdb调试宏的时候,加-g3选项,因为默认的-g选项,级别为2,看不到宏
(gdb) help macro prefix for commands dealing with c preprocessor macros. list of macro subcommands: macro define -- define a new c/c++ preprocessor macro macro expand -- fully expand any c/c++ preprocessor macro invocations in expression macro expand-once -- expand c/c++ preprocessor macro invocations appearing directly in expression macro list -- list all the macros defined using the `macro define' command macro undef -- remove the definition of the c/c++ preprocessor macro with the given name
#
when you put a # before an argument in a preprocessor macro, the preprocessor turns that argument into a character array
宏定义中的#是把跟在后面的参数转换成一个字符串
##分割连接符
在普通的宏定义中,预处理器一般把空格解释成分段标志,对于每一段和前面比较,相同的就被替换。使用空格分段的画,替换之后有空格,如果我们不想要空格,可以用##分隔
1.#define type1(type,name) type name_##type##_type 2.#define type1(type,name) type name _##type##_type 3.#define type2(type,name) type name##_##type##_type
1中,name_是一个段,其中的name没有被宏替换
2和3中,name作为一个段,就会被宏替换。但是2中name和_之间有个空格
宏的相互调用
#define _str(a) #a #define str(a) _str(a) #define cat(a,b) a##b
str(cat(3,5))被处理为:"35"
_str(cat(3,5))被处理为:"cat(3,5)"。因为宏替换只是进行很简单的字符替换。
可变参数宏
iso c标准的可变参数宏定义,类似这个
#define debug(format, ...) fprintf(stderr,format, __va_args__)
对这个宏,"..."指可变参数。在展开时,"..."表示0个或多个符号,包括逗号,一直到括号结束为止。当调用时,那些符号序列将代替里面的__va_args__。
gcc 还支持这样的语法:
#define debug(format, args...) fprintf(stderr, format, args)
这和上面举的那个iso c定义的宏例子是完全一样的,但是这么写可读性更强并且更容易进行描述。
在标准c里,你不能省略可变参数,但是你却可以给它传递一个空的参数。
但是,下面的宏调用在iso c里是非法的,因为字符串后面没有逗号:
debug ("a message")
需要写成这样:
debug ("a message",)
又有了新的问题,上面宏展开后,成了这样:
fprintf(stderr, "a message", )
为了解决这个问题,使用"##"操作,宏改为:
#define debug(format, ...) fprintf (stderr,format, ## __va_args__)
如果可变参数被忽略或为空,‘##'操作将使预处理器去除掉它前面的那个逗号。如果你在宏调用时,确实提供了一些可变参数,gnu cpp也会工作正常,它会把这些可变参数放到逗号的后面。象其它的pasted macro参数一样,这些参数不是宏的扩展。