C语言预处理命令
预处理的概念
以"#"号开头的就是预处理命令,在源程序中这些命令都放在函数之外,而且一般都放在源文件的前面,它们称为预处理部分 所谓预处理是指在进行编译的第一遍扫描(词法扫描和语法分析)之前所作的工作,预处理是C语言的一个重要功能,它由预处理程序负责完成.当对一个源文件进行编译时,系统将自动引用预处理程序对源程序中的预处理部分作处理,处理完毕自动进行对源程序的编译 C语言提供了多种预处理功能,如:宏定义、文件包含、条件编译等.合理地使用预处理功能编写的程序便于阅读、修改、移植和调试,也有利于模块化程序设计。
宏及条件编译:
宏的概念
被定义为"宏"的表示符称为"宏名"。在编译预处理时,对程序中所出现的"宏名",都用宏定义中的字符串去代换,这称为"宏代换“或”宏展开" 宏定义是由源程序中的宏定义命令完成的,宏代换是由预处理程序自动完成的.在C语言中,"宏分为有参和无参数两种" 无参宏的宏名后不带参数,其定义的一般形式为: #define 标示符 字符串 # 表示这是一条预处理命令,凡是以"#"开头的均为预处理命令 define 为宏定义命令 标示符 为所定义的宏名 字符串 可以是常数、表达式、格式串等
注意事项:
1.习惯上宏名用大写字母表示,以便于与变量区别,但也允许用小写字母 2.宏定义时用宏名来表示一个字符串,在宏展开时又以该字符串取代宏名,这只是一种简单地代换,字符串中可以含任何字符,可以是常量,也可以是表达式,预处理程序对它不作任何检查.如有错误,只能在编译已被宏展开后的源程序时发现 3.宏定义不是说明或语句,在行末不必加分号,如加上分号则连分号也一起置换 4.宏定义必须写在函数之外,其作用域为宏定义命令到源程序结束.如要终止其作用域可使用 #undef命令 5.宏定义允许嵌套 #define R 4 #define PI 3.14 #define AREA R*PI //嵌套定义 6.宏名在源程序中若用 "" 括起来,则预处理程序不对其做宏代换 7.可用宏定义表示数据类型,使书写方便 #define INT int INT a; a=10; //相当于用宏给 int 起了一个别名 #define P struct Person P{ int age; }; P p1= {24};
有参宏的定义方法和使用
C语言允许宏带有参数.在宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数 对带参数的宏,在调用中,不仅要宏展开,而且要用实参去代换形参 带参宏定义的一般形式为: #define 宏名(形参1,形参2...) 字符串 带参宏调用的一般形式为: 宏名(实参1,实参2..); 例: #define SUM(a) a+a int result=SUM(3); printf("%d \n",result);
有参宏使用的注意事项
1.带参宏定义中,形参之间可以出现空格,但是宏名和形参表之间不能有空格出现 2.在带参宏定义中,形式参数不分配内存单元,因此不必作类型定义.而宏调用中的实参是具体的值.要用它们去代换形参,因此必须作类型说明.这是与函数中的情况不同的.在函数中,形参和实参是两个不同的量,各有自己的作用域,调用时要把实参值赋予形参,进行"值传递"。而在带参宏中,只是符号代换,不存在值传递的问题 3.在宏定义中的形参是标识符,而宏调用中的实参可以是表达式 4.在宏定义中,字符串内的形参通常要用括号括起来以避免出错,在上例中的宏定义中(y)*(y)表达式的y都用括号括起来,因此结果是正确的 例如:#define SUM(x,y) (x)*(y)+(x)+(y) 5.宏定义也可用来定义多个语句,在宏调用时,把这些语句又代换到源程序内 例:#define M3(m,n) m=a+2;n=a*2;
应用:
定义一个有参宏,求最大值 #define MAX(a,b) a>b?a:b
同样定义别名时 #define 和 typedef的区别
宏定义只是简单地字符串代换,宏是在预处理完成的,而typedef是在编译时处理的,它不是作简单地代换,而是对类型说明符重新命名.被命名的标识符具有类型定义说明的功能 例: #define PIN1 int* typedef int *PIN2; PIN1 a,b;//这里的a 是 int* 而b是int PIN2 a1,b1;// 这里a1,b1 都是int* 产生差异的原因在于 一个是预处理阶段 一个是编译阶段
条件编译的概念和优点:
1.为什么要使用条件编译
1)按不同的条件去编译不同的程序部分,因而产生不同的目标代码文件.有利于程序的移植和调试 2)条件编译当然也可以用条件语句来实现.但是用条件语句将会对整个源程序进行编译,生产的目标代码程序很长,而采用条件编译,则根据条件只编译其中的程序段1或程序段2,生产的目标程序较短
2. #if-#else条件编译指令
格式: #if 常量表达式 程序段1 #elif 常量表达式 程序段2 #else 程序段3 #endif 缺点: 判断的依据是宏定义中的数据,而不是编译器中的
3 #ifdef用来半段某个宏是否定义,定义为ture
例: int a =0; #ifdef DEBUG a =10; #else a=1000; #endif
4. #ifndef 用来判断某个宏是否定义,没定义为true
当使用条件编译指令调试BUG,类似于JAVA中的LOG管理
条件:
DEBUG1 = 1 显示调试信息
DEBUG1 = 0 不显示调试信息
#define DEBUG=1 #if DEBUG1==1 #define Log(format,...) printf(format,## __VA_ARGS__); #elif DEBUG1==0 #define Log(format,...) #else #define Log(format,...) #endif 使用 Log("XXXXX-->",10); //format 代表形参 ...表示可变参数 也类似于java中的泛型 //##标示可以有参数也可以没有参数 ,如果没有##就至少有一个参数