宏定义
#define指令(简单的宏) 替换列表
宏的替换列表可以包括标识符、关键字、数值常量、字符常量、字符串字面量、操作符和排列。当预处理器遇到一个宏定义时,会做出一个“标识符”代表“替换列表”的记录。在文件后面的内容中,不管标识符在哪里出现,预处理器都会用替换列表代替它。
- 程序会更易读
- 程序会更易于修改
- 可以帮助避免前后不一致或键盘输入错误
- 可以对C语法做小的修改
- 对类型重命名
- 控制条件编译
列子
#define STE_LEN 80
#define TRUE 1
#define FALSE 0
#define PI 3.1415923
#define CR '\r'
#define EOS '\0'
#define MEM_ERR "Error: not enough memory"
带参数的宏(也称为函数的宏)
-
程序可能会稍微快些
-
宏更“通用”
-
编译后的代码通常会变大
-
宏参数没有类型检查
-
无法用哦一个指针来指向一个宏
-
宏可能会不止一次地计算它的参数
列子
#define MAX(x, y) ((x) > (y) ? (x) : (y))
#define IS_EVEN(n) ((n) % 2 == 0)
//带参数的宏可以包含空的参数列表
#define getchar() getc(stdin)
int i = 0;
int j = 1;
if (IS_EVEN(i)) {
i = MAX(i, j);
i++;
}
宏的替换列表可以包含对其它宏的调用。
#define TWO_PI (2 * PI)
预处理器只会替换完整的记号,而不会替换记号的片段。宏定义的作用范围通常到出现这个宏的文件末尾。
宏不可以被定义两遍,除非新的定义与旧的定义是一样的。可以使用 #undef 指令“取消定义”。
宏定义中最好加上圆括号。
创建较长的宏
在创建较长的宏时,逗号运算符十分有用。
#define ECHO(s) (gets(s), puts(s))
条件编译
#if 指令 与 #endif 指令,及 #defined
#define DEBUG 1
#if DEBUG
printf("xxx %d\n", i);
#endif
当预处理器遇到 #if 指令时,会计算常量表达式的值。如果表达式的值为0,那么 #if 与 #endif 之间的行将在预处理过程中从程序删除;否则, #if 与 #endif 之间的行会被保留在程序中,继续留给编译器处理,这时 #if 与 #endif 对程序没有任何影响。
#defined 运算符:但 defined 应用于标识符时,如果标识符是一个定义过的宏则返回1,否则返回0。defined 运算符通常于 #if 指令结合使用
#if defined DEBUG
// ...
#endif
#ifdef 指令 和 #ifndef 指令
#ifdef 指令测试一个标识符是否已经定义为宏,与 #if 指令类似。严格来说,并不需要 #ifdef,因为可以结合 #if 指令和 defined 运算符来得到相同的效果
#ifndef 指令与 #ifdef 指令类似,但测试的是标识符是否没有没定义为宏。
#elif 指令和 #else 指令
在 #if 指令和 #endif 指令之间可以有任意多个 #elif 指令,但最多只能有一个 #else 指令
编写在多台机器或多种操作系统之间可移植的程序,编写可以用不同的编译器编译的程序,为宏提供默认定义,临时屏蔽包含注释的代码。
#error 消息
当遇到时会显示一条包含消息的出错消息。
#line n
用来改变程序行编号的方式,也可以使用这条指令使编译器认为它正在从一个有不同名字的文件中读取程序。
#pragma 记号
要求编译器执行某些特殊操作提供了一种方法