C语言预处理技巧

C语言预处理技巧

1.宏处理(#define)

函数定义式


#define MAX(a, b) ((a)>(b)?(a):(b))
k = MAX(i&0x0f, j&0x0f)//比较大小

注意这种函数式宏定义和真正的函数调用有什么不同:

1、函数式宏定义的参数没有类型,预处理器只负责做形式上的替换,而不做参数类型检查,所以传参时要格外小心。

2、调用真正函数的代码和调用函数式宏定义的代码编译生成的指令不同。如果MAX是个真正的函数,那么它的函数体return a > b ? a : b;要编译生成指令,代码中出现的每次调用也要编译生成传参指令和call指令。而如果MAX是个函数式宏定义,这个宏定义本身倒不必编译生成指令,但是代码中出现的每次调用编译生成的指令都相当于一个函数体,而不是简单的几条传参指令和call指令。所以,使用函数式宏定义编译生成的目标文件会比较大。

3、定义这种宏要格外小心,如果上面的定义写成#define MAX(a, b) (a>b?a:b),省去内层括号,则宏展开就成了k = (i&0x0f>j&0x0f?i&0x0f:j&0x0f),运算符的优先级就错了。同样道理,这个宏定义的外层括号也是不能省的,想一想为什么。

#、##运算符和可变参数
在函数式宏定义中,#运算符用于创建字符串,#运算符后面应该跟一个形参(中间可以有空格或Tab),例如:

#define STR(s) # s
STR(hello 	world)

##运算符不仅限于函数式宏定义,变量式宏定义也可以用。例如:

#define CONCAT(a, b) a##b
CONCAT(con, cat)
//预处理之后是concat

使用用法及注意

调用函数式宏定义允许传空参数,这一点和函数调用不同,通过下面几个例子理解空参数的用法。

#define FOO() foo
FOO()
预处理之后变成foo。FOO在定义时不带参数,在调用时也不允许传参数给它。

#define FOO(a) foo##a
FOO(bar)
FOO()
预处理之后变成:

foobar
foo
FOO在定义时带一个参数,在调用时必须传一个参数给它,如果不传参数则表示传了一个空参数。

#define FOO(a, b, c) a##b##c
FOO(1,2,3)
FOO(1,2,)
FOO(1,,3)
FOO(,,3)
//预处理之后变成:

//123
//12
//13
//3
//FOO在定义时带三个参数,在调用时也必须传三个参数给它,空参数的位置可以空着,但必须给够三个参数,FOO(1,2)这样的调用是错误的。

#define FOO(a, ...) a##__VA_ARGS__
FOO(1)
FOO(1,2,3,)
//预处理之后变成:

//1
//12,3,
//FOO(1)这个调用相当于可变参数部分传了一个空参数,FOO(1,2,3,)这个调用相当于可变参数部分传了三个参数,第三个是空参数。
发布了15 篇原创文章 · 获赞 1 · 访问量 531

猜你喜欢

转载自blog.csdn.net/weixin_42323243/article/details/103369451
今日推荐