Summary
1)#define
是预处理器
解决的单元实体之一,在预编译期进行文本替换
2)#define
定义的宏能够呈现在程序的任意中央
,定义之后的代码都能够应用
3)#define
能够定义宏常量,实质上是字面量
4)define
能够定义表达式,应用上相似函数
;性能可能更弱小
(类型能够作为参数、求数组大小);更容易出错
(当和其余运算混合在一起时)
5)宏因为是间接文本替换,所以没有任何的调用开销
;宏表达式里不能呈现递归
;宏被预处理器解决,所以编译器不晓得宏的存在
,天然宏也不会有作用域的概念
,作用域是针对变量和函数的
。
6)罕用的预约义宏
宏 | 含意 | 示例 |
__FILE__ | 被编译的文件名 | file1.c |
__LINE__ | 以后行号 | 25 |
__DATE__ | 编译时的日期 | Jan 31 2012 |
__TIME__ | 编译时的工夫 | 17:01:01 |
__STDC__ | 编译器是否遵循规范C标准 | 1 |
宏定义与应用剖析
#define
是预处理器
解决的单元实体之一#define
定义的宏能够呈现在程序的任意地位
#define
定义之后的代码都能够应用这个宏
1、#define定义的宏常量
#define
定义的宏常量能够间接应用,实质为字面量
(不会占用内存,字符串字面量会存在只读存储区)
// test.c中 上面的宏定义正确么?#define ERROR -1#define PATH1 "D:\test\test.c"#define PATH2 D:\test\test.c#define PATH3 D:\test\test.cint main(){ int i = ERROR; char* p1 = PATH1; char* p2 = PATH2; char* p3 = PATH3; return 0;}
单步编译gcc -E test.c -o test.i ==> 预编译,生成两头文件.igcc -S test.i -o test.s ==> 编译,生成汇编文件.s
剖析:在第一步预编译阶段,解决define并生成.i文件,这时候不会出错;下一步编译阶段,将两头文件转换为汇编文件时,就会报错。
起因在于:在预编译的阶段,仅仅是做文本替换,没有语法查看
;到了编译阶段,会对替换后的.i文件进行语法查看
,再生成汇编文件,这时候语法查看就出错了。
2、#define定义的表达式
#define
表达式的应用相似函数调用
#define
表达式能够比函数更弱小
#define
表达式比函数更易出错
#define SUM(a, b) (a) + (b)#define MIN(a, b) ((a) < (b) ? (a) : (b))#define DIM(a) sizeof(a) / sizeof(*a)int main(){ int a = 1; int b = 3; int c[2] = {0}; // expected: 4, 1, 2 printf("SUM(a, b) = %d\n", SUM(a, b)); printf("MIN(a, b) = %d\n", MIN(a, b)); printf("size of array = %d\n", DIM(c)); // unexpected: 3 printf("unexpected: %d", MIN(++a, b)); // 冀望失去++a和b中的较小的值:2 return 0;}
剖析:
- define表达式
相似
函数调用,像下面的例子中,printf中宏的定义就很像是函数调用。 - define表达式可能
比函数更弱小
,如上,DIM宏能够求数组的大小
,然而在C语言中无奈通过函数求一个数组的大小
,因为当数组作为函数的参数时,会进化成指针
;再比方,C语言中不能把类型作为参数
,然而宏就能够。 - define表达式
更容易出错
,如上,MIN(++a, b)冀望失去的值为2,理论失去的值却是3。由单步编译失去的后果能够看出,替换后的表达式为((++a) < (b) ? (++b) : (b))
,前置的++被执行了2次,所以失去了3。预编译器就像是一个传话筒,在传话的过程中,就产生了歧义
宏表达式被预处理器
解决,编译器并不知道宏的存在;
宏表达式用“实参”齐全代替形参,不进行任何运算
;
宏表达式没有任何的调用开销
:(因为间接进行文本替换,不像函数须要参数入栈、返回等开销)
宏表达式中不能呈现递归定义:(因为宏只在预处理期进行一次
文本替换,后续的符号编译器就不意识了)
#define SUM(n) ((n>0) ? (SUM(n-1) + n) : 0)int s = SUM(10); // 编译的时候就会报错,undefined reference SUM
3、宏定义的常量或表达式是否有作用域限度?
上面的程序非法么?void def(){ #define PI 3.1415926 #define AREA(r) r*r*PI}double area(double r){ retrun AREA(r);}int main(){ double r = area(10); return 0;}
剖析:编译、运行都不会出错。阐明宏是没有作用域限度的
。只有定义完,前面的代码都能够用。在定义之前应用就会报错undefined reference。作用域只是针对变量和函数的
,宏在预处理期被开展,在编译期曾经没有宏这个货色了
,所以也就没法给宏限定作用域了。
4、 罕用的预约义宏
宏 | 含意 | 示例 |
__FILE__ | 被编译的文件名 | file1.c |
__LINE__ | 以后行号 | 25 |
__DATE__ | 编译时的日期 | Jan 31 2012 |
__TIME__ | 编译时的工夫 | 17:01:01 |
__STDC__ | 编译器是否遵循规范C标准 | 1 |
本文总结自“狄泰软件学院”唐佐林老师《C语言进阶课程》。
如有错漏之处,恳请斧正。