前言
预处理(预编译)指在进行编译的第一遍扫描(词法扫描和语法分析)之前所作的工作。预处理指令可放在程序中任何位置。
预处理由预处理程序负责完成。
C语言提供多种预处理功能,主要处理#
开始的预编译指令。
宏定义
在编译预处理时,对程序中所有出现的表示服,都用宏定义中的字符串去替换,这称为宏替换或宏展开。
宏定义分为有参数和无参数两种。
无参宏定义
形式
#define 宏名 字符串
- 以#开头的均为预处理命令。
- “define”为宏定义命令。
- “标识符”为符号常量,即宏名。
- “字符串”可以是常数、表达式、格式串等。
在宏展开时会以字符串取代标识符。这只是一种简单的文本替换,预处理程序对它不作任何检查
。
注意理解宏替换中“换”的概念,即在对相关命令或语句的含义和功能作具体分析之前就要进行文本替换。
有参宏定义
#define 宏名(形参) 表达式
例子
#define INC(x) x+1 //宏定义
y = INC(5); //宏调用
条件编译
当需要对编译的内容进行有选择性的编译时需要用到条件编译。
条件编译有三种形式,下面分别介绍。
#ifndef
它是if not define 的简写,是宏定义的一种,实际上确切的说,这应该是预处理功能三种(宏定义、文件包含、条件编译)中的一种—-条件编译。
注意事项
#ifndef 和 #endif 要一起使用,如果丢失#endif,可能会报错。
例子
Windows 有专有的宏_WIN32
,Linux 有专有的宏__linux__
void main(void){
if(_WIN32){
printf("This is Windows platform");
}else if(__linux__){
printf("This is Linux platform");
}else{
printf("This is Other platform");
}
}
但这段代码是错误的,在 Windows 下提示 __linux__
是未定义的标识符,在 Linux 下提示 _Win32 是未定义的标识符。对上面的代码进行改进:
void main(void){
#if _WIN32
printf("This is Windows platform");
#elif __linux__
printf("This is Linux platform");
#else
printf("This is Other platform");
#endif
}
#define
在C或C++语言源程序中允许用一个标识符
来表示一个字符串,称为“宏”。“define”为宏定义命令。
被定义为“宏”的标识符称为宏名
。在编译预处理时,对程序中所有出现的宏名
,都用宏定义中的字符串去代换,这称为宏代换
或宏展开
。宏定义是由源程序中的宏定义命令完成的。宏代换是由预处理程序自动完成的。
优点:
- 方便程序的修改。这个就不多说了。
- 提高程序的运行效率。使用带参数的宏定义可完成函数调用的功能,又能减少系统开销,提高运行效率。正如C语言中所讲,函数的使用可以使程序更加模块化,便于组织,而且可重复利用,但在发生函数调用时,需要保留调用函数的现场,以便子函数执行结束后能返回继续执行,同样在子函数执行完后要恢复调用函数的现场,这都需要一定的时间,如果子函数执行的操作比较多,这种转换时间开销可以忽略,但如果子函数完成的功能比较少,甚至于只完成一点操作,如一个乘法语句的操作,则这部分转换开销就相对较大了,但使用带参数的宏定义就不会出现这个问 题,因为它是在预处理阶段即进行了宏展开,在执行时不需要转换,即在当地执行。宏定义可完成简单的操作,但复杂的操作还是要由函数调用来完成,而且宏定义所占用的目标代码空间相对较大。所以在使用时要依据具体情况来决定是否使用宏定义。
在C或C++语言中,“宏”分为有参数和无参数两种。
一、无参宏定义
1. 无参宏定义的一般形式为:#define 标识符 字符串
2. 其中的“#”表示这是一条预处理命令。凡是以“#”开头的均为预处理命令。“define”为宏定义命令。“标识符”为所定义的宏名。“字符串”可以是常数、表达式、格式串等。