预处理是程序编译前的一个预先处理的动做,编译一共有4个步骤:C原文件 --> 预处理 --> 编译 --> 汇编 -> 连接 --> 可执行文件。
预处理的工做主要是展开咱们C源码中的#开头的语句,去掉了全部的注释,在严格的意义来讲,这些语句它并不属于C语言的语法范畴。
如下是预处理的一些指令:
1.头文件 : #include
2.宏定义 : #define
3.取消宏 : #undef
4.条件编译 : #if \ #ifdef \ #ifndef \ #else \ #elif \ #enif
5.显示错误 : #error
6.修改当前文件的名字行号 :#line
7.向编译器中发送特定的指令 : #progma
能够在编译程序的时候添加一个-E的选项,让编译器在预处理以后停下来不要继续往下走,macro.i是源程序将#展开的内容。数组
gcc macro.c -o macro.i -E
宏(macro)实际上以一段字串,在源码中只是用来直接替换目标位置,通常宏都使用全大写字母(这只是一个习惯)。函数
#define PI 3.141592 #define BUF_SIZE 64 int main (int argc, char const *argv[]){ printf("PI:lf\t" , PI); int a = 100 + PI ; printf("a:%d\n", a); } 输出:PI:3.141592 a:103
注意:
1.PI就是一个宏,在咱们的源代码中若是出现宏的使用,则经过预处理以后会直接被替换,只是直接的字符替换而已,不会考虑语法或运算关系。code
无参宏意味着咱们在使用的时候不须要传递参数内存
#define BUF_SIZE 64 int main (int argc, char const *argv[]){ int arr[BUF_SIZE]; //定义了一个int型数组,大小为64个 }
注意:
1.宏他的本指就值直接的替换,没有任何的语法检查;
2.使用宏的状况下若是代码有跟新迭代时,只须要修改宏的一处,整个代码中全部用到宏的地方都会被修改;
3.宏的名字能够提升代码的可读性。编译器
带参宏 在使用的时候须要携带参数来使用。源码
#define MAX(a,b) a>b ? a : b int main (int argc, char const *argv[]){ printf("%d\t" , MAX(100,998) ); printf("%d\n" , 100>998 ? 100 : 998 ); } 输出:998 998
注意:
1.使用带参宏的时候也是直接替换。
2.只是存粹的文本替换,没有任何的语法检查/判断,也没有任何的运算
3.宏在预处理以后已经被替换,代码实际运行时是不须要额外的时间开销,只会浪费一点内存的空间。编译
因为宏只是存粹的文本替换,中间不涉及任何的计算与语法检查,类型匹配,因此用起来会比用函数麻烦不少。gcc
#define MAX(a,b) a>b ? a : b int main (int argc, char const *argv[]){ int x = 100; int y = 200; printf("MAX:%d\n" , MAX(x,y == 200 ? 888:999 ) );
从以上的代码中, 无论表达式 y == 200 ? 888:999 的值都是大于 x ,可是却出来最大值为x 、
观察一下替换后的结果:语法
printf("MAX:%d\n" , x>y == 200 ? 888:999 ? x : y == 200 ? 888:999 ); //注意从右向左运算,?的优先级大于:
因此应该修改长以下:gc
#define MAX(a,b) (a)>(b) ? (a) : (b) printf("MAX:%d\n" , (x)>(y == 200 ? 888:999) ? (x) : (y == 200 ? 888:999) );
使用括号对宏当中的每一项括起来,提升优先级,这样替换以后逻辑不会出现问题。