#define 详解
#define 详解#与###undef
文章目录
一、#define定义标识符
1.基本使用方法
常见方法
#define M 100
int main()
{
printf("%d\n", M);
return 0;
}
少见但仍正确的用法:
#define R register
int main()
{
R int a = 100;
//R相当于关键字register
return 0;
}
当然#define还有其它用法(难以置信但合理的),如:
#define do_forever for(;;)
#define CASE break;case
其它可自行探索……
2.#define中的换行
错误的:
正确的:
原因:我们所使用的回车键也是一个字符,加上\将回车转义,使编译器认为这几行仍是一行,避免错误。
3.#define后的;
相信大家都了解#define定义的标识符后不应加;
现在来验证是否应加;(环境:VScode)
相关安装和操作及解释:程序的运行过程
输入指令gcc test.c -E -o test.i生成test.i文件,该文件是将源代码经过预编译形成的文件。此时可以看到编译器将M替换成了100;
可以说明#define定义的标识符会被替换成其定义的内容。因此#define后的;可以加也可以不加。
二、 #define定义宏
#define机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义宏(define macro)。
1.基本使用方法
宏的申明方式: #define name( parament-list ) stuff
其中的 parament-list 是一个由逗号隔开的符号表,它们可能出现在stuff中。
注意: 参数列表的左括号必须与name紧邻。 如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分
此时输入指令生成test.i文件,test.i为经过预编译的文件,结果如下:
可以看到与#define定义标识符一样的操作。(该操作方便理解下文的内容)
2.#define定义的宏建议加( )
如:
为什么应该加上( )呢?我们先讨论内部( )
相信大家都遇到过这个问题:明明输入的x的值为3+2,结果却是11而不是25
寻找原因,生成test.i文件,观察经过预编译后生成的文件:
可以看出编译器并不会先计算3+2再进行运算,而是直接进行替换,因此需要加上( )来保证结果的正确性。
接下来讨论外部( )
举个例子来直观感受:
生成test.i文件后来观察原因:
不用我解释,大家也能明白原因。因此在加内部( )时也需加上外部( )
三、#define替换规则
在程序中扩展#define定义符号和宏时,需要涉及几个步骤。
- 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先被替换。
- 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换。
- 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。
注意:
- 宏参数和#define 定义中可以出现其他#define定义的符号。但是对于宏,不能出现递归。
- 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。
四、带副作用的宏参数
当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么你在使用这个宏的时候就可能出现危险,导致不可预测的后果。副作用就是表达式求值的时候出现的永久性效果。
例如:
x+1;//不带副作用
x++;//带有副作用
举例:大家可以计算一下打印的a、b、c的值是什么
转化为test.i文件后为:
注意:
那么如果MAX是函数呢?
与宏MAX不同,函数MAX的结果是4、5、4。这是为什么呢?原因如下:与宏不同,函数传参时传的是计算好的值,而非整个替换进去。
因此可以看出该宏参数是有副作用的。
五、#undef 移除宏定义
这条指令用于移除一个宏定义
举例:
六、#与##
1.#的作用
#用于将参数插入字符串中。
举例:用#define编写一个打印函数:
其中打印结果为:
现在我们希望x替换成a、b、c
那么就需要预处理指令#了,具体做法如下:
注意:#应用于两个字符串之间。
若不使用#则结果如下:
2.##的作用
##可以把位于它两边的符号合成一个符号。 它允许宏定义从分离的文本片段创建标识符。
更多推荐
所有评论(0)