预处理器是在编译C程序之前对程序进行编辑的工具,它的行为依赖于以#
开头的预处理指令。
预处理器在执行指令时可能产生非法的程序,而由于编译的是预处理器编辑过的版本,难以根据错误信息查找错误原因,检查预处理器的输出是解决这个问题的有效途径。gcc
提供了-E
选项支持只进行预处理将预处理后的文件显示在控制台上,配合-o
可以将预处理后的程序存放在指定文件中。使用-save-temps
选项可以保留gcc
命令执行过程中的所有中间文件,例如预处理后的结果文件,汇编代码文件和目标文件等。
/**************************************
* prepocessor_result.c *
* *
* C语言查看预处理输出 *
**************************************/
#define N 10
int main()
{
int n = N;
int m = N + 10;
return 0;
}
使用-E
选项将预处理结果输出到命令行窗口
使用-E
和-o
选项将预处理结果输出到文件
使用-save-temps
选项输出所有中间文件,其中.i
文件为预处理后文件。
预处理指令
预处理指令主要包括以下四类:
- 宏定义。包括
#define
和#undef
指令,前一个指令用以定义一个宏,后一个指令是删除一个宏。 - 文件包含。
#include
指令,将一个指定的文件包含到程序中。 - 条件编译。包括
#if
,#ifdef
,#ifndef
,#elif
,#else
和#endif
指令,根据条件判断是否将一段文本加入程序。 - 特殊指令。
#error
,#line
,#pragma
。
预处理指令需要满足以下规则:
- 指令以
#
开始,除注释外,独占一行或多行,不需要使用;
或其他特殊标记结尾。 - 指令的符号间可以加入任意数量的空格或横向制表位。
- 指令总在第一个换行符结束,除非利用
\
明确声明继续。 - 指令可以出现在程序的任何地方。
宏定义
宏定义可以定义两类宏,一类是简单的宏,一类是带参数的宏。
简单的宏
简单的宏的定义格式如下:
#define 宏名称 替换列表
替换列表是任意C语言标记,包括字符串,字符变量,运算符等等,看可以为空。当预处理遇到宏定义时,会记录该宏名称和它的替换列表,将文件后面的内容中出现宏名称用替换列表替换。宏名称常全部使用大写字母。
简单的宏常用来定义具有明确意义的常量,这样可以增加程序的易读性、易修改性,还可以避免多次输入同一个值不一致错误等。除了用于常量定义,简单的宏还可以通过为C语言的符号添加别名的方式改变C语言语法或发明自己的语言等,重命名类型以及根据宏定义控制条件编译等。
/**************************************
* simple_macro.c *
* *
* C语言中的简单宏 *
**************************************/
#include <stdio.h>
/*改变语法*/
#define LOOP for (;;)
#define BEGIN {
#define END }
/*定义常量*/
#define PRICE 3.52
/*类型重命名*/
#define BOOL int
/*控制条件编译*/
#define PRINT
int main()
{
int i =