1、预处理指令的概念及分类。
1)预处理
源代码在编译成机器指令之前,要进行预处理。预处理阶段可以根据预处理指令,(以#开头)执行 一些列操作。预处理可以在编译之前处理及修改C源代码。完成预处理阶段,并分析及执行了所有的预 处理指令之后,这些指令就不再出现在源代码中。编译器开始编译阶段,生成与程序对应的机器码。 咱们之前的所有列子都使用了预处理指令,如#include 和 #define 指令。include(包含) 我们之前学习过。
2)替换程序代码
程序在编译之前,预处理器指令会替换源代码中的符号。最简单的符号替换前面已经介绍过。列入使用预处理器指令将字符串PI替换为特定值: #define PI 3.14159265 。标示符PI 看起来像变量。 但是它不是变量,与变量一点关系也没有。PI是一个标志,作用在预处理阶段用来替换在#define指令中指定的一串数字。当预处理完成后,准备编译程序时,PI字符串已经被它的 定义取代。不再出现了。
printf("%f",PI); 预编译是指令, 不到需要的时候 不要放语句结束符 ” ; “
2、宏的概念
宏基于前面的#define指令,但它的适用范围比较大,不仅可以使用固定的字符串代替某些代码,可以进行参数化的代换,这个代换也叫宏展开或者宏代换。这样我们C语言中宏就可以分为两个类型了。一种是无参数宏,一种是有参数宏。二者在定义时的一般形式为:
无参宏:#define 宏名 字符串
有参宏:#define 宏名(形参表) 字符串
3、无参宏使用注意事项
· 习惯上宏名也是标示符,用大写字母表示,以便与变量区别。但也允许用小写字母。 · 字符串可以是常量,表达式,格式串,数据类型等,写什么都会原封不动的替换掉。 · 分号,宏定义是指令,末尾不加分号。
· 定义位置,作用域。定义必须写在函数外面,作用域为宏定义命令到源程序结束。
· 终止作用域可以使用#undef命令。
· 嵌套定义
无参数宏定义 一般形式
#define 宏名 字符串
作用: 用宏名替换字符串,简化操作,降低编码错误。
注意事项:
1、宏名 : 标示符 一般为大写字母,便于跟不同的变量区分,
2、字符串 :原封不动的替换,常量,表达式,格式字符串, 可以嵌套定义 作用域: 从定义位置开始,到源文件结束
3、终止: #undef 命令终止。
4、有参宏
1)有参宏定义
带参宏 定义 的一般形式为:
#define 宏名(形参表) 字符串
在宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数。 参数列表中放形参,字符串中放置形参的操作。 对带参的宏,在调用中, 不仅要宏展开,而且要用实参去代换形参。
调用形式:
宏名(实参表);
实例:
#define W(y) y+1 printf("%d \n",W(3));
2)有参宏使用注意事项 · 定义符合规范。如:
形参之间可以出现空格,但是宏名和形参表之间不能有空格出现。
· 形参只是简单的符号代换,不需要分配内存空间,不存在值传递问题。
· 通常加括号利于代码的可读性。
· 字符串可以放多个语句。
· printf语句的定义为Log模式。
#define Log(format,...) printf(format,## __VA_ARGS__)。这里,‘...’指可变参数。这类宏在被调用时,##表示成零个或多个参数,包括里面的逗 号,一 直到到右括弧结束为止。当被调用时,在宏体(macro body)中,那些符号序列集合 将代替里面 的__VA_ARGS__标识符。
举例:
#define SUM(a) a+a
#define M1(x ,y) (x)*(y)+(x)+(y)
#define M2(a) a+3*y
#define M3(m,n) m = a+2;n=a*2;
5、#define和typedef的区别
应注意用宏定义表示数据类型和用typedef定义数据说明符的区别。宏定义: 只是简单的字符串代换,在预处理阶段完成。typedef: 对类型说明符重新命名。在编译的时候处理。用来表示新命名的标示符具有类型定义说明的功能。
6、使用条件编译指令屏蔽调试bug
/*
通过控制 MyDEBUG1 的值来控制编译
*/
#define MyDEBUG1 1
#if MyDEBUG1 == 0
//format是格式控制,##表示可以没有参数,__VA_ARGS__表示变量
#define Log(format,...) printf(format,## __VA_ARGS__)
#else
#define Log(format,...)
#endif
void test(){
Log("xxxxx");
}
int main(int argc, const char * argv[]) {
Log("%d\n",10);
return 0; |
|