define定义的宏详解
今天书接上回,接着聊关于预编译和#define的知识。
今天也要心情愉悦哦。
预定义的一些符号和指令
FILE //进行编译的源文件
LINE //文件当前的行号
DATE //文件被编译的日期
TIME //文件被编译的时间
STDC //如果编译器遵循ANSI C,其值为1,否则未定义
define定义宏
定义带参数的宏
#define name( parament-list ) stuff
其中的 parament-list 是一个由逗号隔开的符号表,它们可能出现在stuff中。
注意:
1.参数列表的左括号必须与name紧邻。
2.如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分。
看个例子:
#define SQUARE(a) (a*a)int main(){int a = 9;printf("%d", SQUARE(a));return 0;}
这是定义一个宏来进行求一个数的平方,需要注意的点是SQUARE后面的()必须紧挨着不能有空格,而且宏内容尽量带上(),为了防止一些因为符号带来的计算错误。
就比如,还是还是上面的宏,如果我要是传(4+5)呢?
#define SQUARE(a) (a*a)int main(){printf("%d", SQUARE(4+5));return 0;}
这样就好像跟我们想象中不一样,为什么是29呢?
首先宏参数也是仅仅是替换的关系,所以替换后变成了(4+5*4+5),这样看的话就变成了29,所以要尽量带上()。
修改后变成了,就不会出错了。
#define SQUARE(a) ((a)*(a))int main(){printf("%d", SQUARE(4+5));return 0;}
tip:
用于对数值表达式进行求值的宏定义 都应该用这种方式加上括号, 避免在使用宏时由于参数中的操作符或 邻近操作符之间不可预料的相互作用。
有副作用的宏参数
那么在宏参数上还有要一点注意的,就是宏参数在宏内容上被多次使用时,要考虑副作用。
看个例子:大家可以计算下结果
#define CMP(a,b) (a>b?a:b)int main(){int a = 10;int b = 20;int c = CMP(a++, b++);printf("a = %d\n", a);printf("b = %d\n", b);printf("c = %d\n", c);return 0;}
这里,就会发现,这里的参数就奇怪,传的是a++和b++,这里的宏参数就有副作用,就会导致结果不太一样,这里是把a++和b++直接进行替换,比较时,a++进行1次,b++执行了两次,赋值给c时是b++一次的结果。
宏替换的规则
在程序中扩展#define定义符号和宏时,需要涉及几个步骤。
- 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先被替换。
- 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换。
- 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。
注意:
1. 宏参数和#define 定义中可以出现其他#define定义的符号。但是对于宏,不能出现递归。
2 . 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索
3. 是先替换宏参数中的值,在替换宏本身
看个例子 :
#define M 10int main(){printf("M is %d", M);return 0;}
其中"M is %d"中的M不会被替换,而后面的M会被替换。
#和##的作用
#的作用
就上述的例子,如果我们就是想替换字符串中的呢?怎么办?
在C语言中有个很有意思的东西,一起看看把
int main(){printf("胡杨树下\n");printf("胡杨""树下""\n");return 0;}
这样看的话,就是字符串之间是没有换行就可以一行输出,效果一样。那么我们可以使用 #把参数插入字符串中。
例:
#define PRINT(FORMAT,NUM) printf\("the numeber of "#NUM " is " FORMAT"\n",NUM)int main(){int a = 0;int b = 0;int c = 0;scanf("%d %d %d", &a,&b,&c);PRINT("%d", a);PRINT("%d", b);PRINT("%d", c);return 0;}
这里可以看是通过宏和#的作用是可以达到上述的效果的。
#的作用也就看出了,#的作用是把宏参数变成相对应的字符串。
那么##的作用的?
也比较少见,看个例子 :
#define LINK(huayang,shuxia) (huyang##shuxia)int main(){int huyangshuxia = 10;printf("%d\n", LINK(huyang, shuxia));return 0;}
##的作用是,可以把位于它两边的符号合成一个符号。它允许宏定义从分离的文本片段创建标识符。就像拼图一样,把两个符号,合成一个由宏定义的符号。
下期预告:
因为预处理知识太多了,害怕各位看官没有耐心,
本期就到这里结束,下期继续,下期更精彩~~~