一:预定义符号
C语言中设置了一些预定义符号,它们可以直接使用,同时预定义符号是在预处理期间处理的。
以下就是相关的预处理符号的作用。
二:#define定义常量
首先基本的语法是 #define name stuff 相对比较简单,就不多赘述了。
但是有些朋友就有所困惑了,这个最后是否要加";",这里声明一下是不用加的。
三:#define定义宏
#define 机制包括了⼀个规定,允许把参数替换到⽂本中,这种实现通常称为宏(macro)或定义宏 (define macro)。
申请宏的基本形式是
#define name(paramentf-list) stuff
这里需要注意一下,name的后面是不能空格的,括号应该与name紧密相连。如果有空隙的话就会被解释成stuff的一部分。
这样看着并不是很好懂,我们接下来就举一个例子来理解其中的意思。
#define SQUARE(x) x*x
int a=3;
printf("%d/n",AQUARE(a));
这个宏接收⼀个参数 x .如果在上述声明之后,你把 SQUARE( 3 ); 置于程序中,预处理器就会⽤
下⾯这个表达式替换上⾯的表达式: 3 * 3
注意:
宏使用不当也存在一定的问题。我们可以观察下面的代码段。
#define SQUARE(x) x*x
int a=3;
printf("%d/n",AQUARE(a+1));
这个乍一看是两个4相乘为16,但是恰恰不同,这个结果是7,
因为在替换文本的时候,参数x被换成a+1,那么就是a+1*a+1,这个时候就要遵循运算法则,计算的结果是2a+1.
所以我们可以加两个括号,来避免这种错误。
#define SQUARE(x) (x)*(x);这样就是(a+1)*(a+1),避免了那种错误。
但是这种也并非十分的完美。我们可以继续看下面的例子。#define SQUARE(x) (x)+(x)
int a=3;
printf("%d/n",10*AQUARE(a+1));
有同学就会大意的认为这个是90,这个结果是不对的。打印出来的结果是33,错误与上面的差不多,带入进去就是
10*(3)+3;
对于这种情况我们的解决办法是在宏定义表达式两边加上⼀对括号就可以了。
#define SQUARE(x) ((x)+(x))。这个就比较完美了。
注意:
所以用于对数值表达式进行求值的宏定义都应该用这种方式加上括号,避免在使用宏时由于参数中的操作符或邻近操作符之间不可预料的相互作用。
四:带有副作用的宏函数
当宏参数在宏的定义中出现超过⼀次的时候,如果参数带有副作用,那么你在使用这个宏的时候就可能出现危险,导致不可预测的后果。副作用就是表达式求值的时候出现的永久性效果。
这句话并不好理解。我们可以举举几个例子来了解其中的意思。
写一个宏,求2个整数的较大值
#define MAX(x,y) ((x)>(y)?(x):(y))int main()
{int a = 3;int b = 5;scanf("%d %d", &a, &b);int m = MAX(a++, b++);int m = ((a++)>(b++)?(a++):(b++));printf("m = %d\n", m);printf("a = %d\n", a);printf("b = %d\n", b);return 0;}
我们可以一步步分析,来解除相应的答案。
首先我们需要将参数带入到宏中,((a++)>(b++)?(a++):(b++));
此时++在后面,那么就是先比较大小然后再加。比较之后b大,然后再加1,此时a为4,b为6.在接下来,到(a++):(b++)这一步因为先使用后加所以m就赋值为6,b再加1.b就为7.
那么答案就是
m=6 a=4 b=7.
如果不是很清晰的话可以参考下面的图片。
五:宏替换的规则
在程序中扩展#define定义符号和宏时,需要涉及几个步骤。
1. 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先被替换。
2. 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换
3. 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。
注意:
1.宏参数和#define 定义中可以出现其他#define定义的符号。但是对于宏,不能出现递归。
2. 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。
这里的字符串常量并不被搜索的意思是
printf("m = %d\n", m);这里面双引号的m并不被替换。
六:宏函数的对比
我们可以总结成下面的表格
希望各位看官有所收获,也麻烦公主少爷们三连,谢谢!!!!!
+