目录
一.#define定义标识符
二.#define定义宏
三.#define替换规则
四. # 和 ##
四.带副作用的宏参数
五.宏和函数的对比
六.命名约定
一.#define定义标识符
语法:
#define name stuff
举几个栗子:
define定义标识符时,不要在最后面加" ; "
二.#define定义宏
#define 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义
宏(define macro)。
下面是宏的申明方式:
#define name( parament-list ) stuff
其中的 parament-list 是一个由逗号隔开的符号表,它们可能出现在stuff中.
注意:
参数列表的左括号必须与name紧邻.
如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分.
三.#define替换规则
在程序中扩展#define定义符号和宏时,需要涉及几个步骤。
1. 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先
被替换。
2. 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换。
3. 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。
注意:
1. 宏参数和#define 定义中可以出现其他#define定义的符号。但是对于宏,不能出现递归。
2. 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。
四. # 和 ##
如何把参数插入到字符串中?
首先我们看看这样的代码:
我们发现字符串是有自动连接的特点的!!!
1. 那我们是不是可以写这样的代码?
#define PRINT(FORMAT, VALUE)\ printf("the value is "FORMAT"\n", VALUE); ... PRINT("%d", 10);
这里只有当字符串作为宏参数的时候才可以把字符串放在字符串中.
另外一个技巧是:
使用 # ,把一个宏参数变成对应的字符串。
比如:
int i = 10; #define PRINT(FORMAT, VALUE)\ printf("the value of " #VALUE "is "FORMAT "\n", VALUE); ... PRINT("%d", i+3);//产生了什么效果?
代码中的 #VALUE 会预处理器处理为:
"VALUE"
最终的输出的结果应该是:the value of i+3 is 13
## 的作用:
1.##可以把位于它两边的符号合成一个符号。
2.它允许宏定义从分离的文本片段创建标识符。
#define ADD_TO_SUM(num, value) \ sum##num += value; ... ADD_TO_SUM(5, 10);//作用是:给sum增加10.
四.带副作用的宏参数
x+1;//不带副作用 x++;//带有副作用
#define MAX(a, b) ( (a) > (b) ? (a) : (b) ) ... x = 5; y = 8; z = MAX(x++, y++); printf("x=%d y=%d z=%d\n", x, y, z);//输出的结果是什么
x=6 y=10 z=9
所以在含有副作用时候要尽量加()!!!
五.宏和函数的对比
属性
#define定义宏
函数
代码长度
每次使用时,宏代码都会被插入到程序中。除了非常小的宏之外,程序的长度会大幅度增长
函数代码只出现于一个地方;每次使用这个函数时,都调用那个地方的同一份代码
执行速度
更快
存在函数的调用和返回的额外开销,所以相对慢一些
操作符号优先级
宏参数的求值是在所有周围表达式的上下文环境里, 除非加上括号,否则邻近操作符的优先级可能会产生 不可预料的后果,所以建议宏在书写的时候多些括号
函数参数只在函数调用的时候求 值一次,它的结果值传递给函 数。表达式的求值结果更容易预测
带有副作用的参数
参数可能被替换到宏体中的多个位置,所以带有副作 用的参数求值可能会产生不可预料的结果
函数参数只在传参的时候求值一 次,结果更容易控制
参数类型
宏的参数与类型无关,只要对参数的操作是合法的, 它就可以使用于任何参数类型
函数的参数是与类型有关的,如 果参数的类型不同,就需要不同 的函数,即使他们执行的任务是 相同的
调试 不便于调试 可以逐语句调试
递归 不能递归 可以递归
六.命名约定
一般来讲函数的宏的使用语法很相似。所以语言本身没法帮我们区分二者。
那我们平时的一个习惯是:
把宏名全部大写
函数名不要全部大写