预处理
注:本文为学习《C语言从入门到精通》时,对部分章节的总结
1、宏定义
1.1、不带参数的宏定义
宏定义指令#define用来定义一个标识符和一个字符串,以这个标识符来代表这个字符串,在程序中每次遇到该标识符时就用所定义的字符串替换它。宏定义的作用相当于给指定的字符串起一个别名。
#define 宏名 字符串
- #表示这是一条预处理命令
- 宏名是一个标识符,必须符合C语言标识符的规定
- 字符串可以是常数、表达式、格式字符串等
- 宏定义不是C语句,末尾不需要“;”
- 如果在字符串中含有宏名,则不进行替换
- 如果字符串长于一行,可以在改行末尾用反斜杠“\”续行
- #define命令出现在程序中函数的外面,宏名的有效范围为定义命令之后到此源文件结束
- 可以用#undef命令(可以在函数中)终止宏定义的作用域
- 宏定义用于预处理命令,它不同于定义的变量,只作字符替换,不分配内存空间
1.2、带参数的宏定义
带参数的宏定义不是简单的字符串替换,还要进行参数替换。
#define 宏名(参数表) 字符串
- 宏定义时,参数要加括号
- 宏扩展必须使用括号来保护表达式中低优先级的操作符
- 对带参数的宏的展开,只是将语句中的宏名后面的括号内的实参字符串代替#define命令行中的形参
- 在宏定义时,宏名与带参数的括号之间不可以加空格
- 在带参宏定义中,形参不分配内存
2、#include指令
#include “stdio.h” // 系统先在用户当前目录中寻找,找不到,再到存放C库函
数头文件所在目录中寻找
#include <stdio.h> // 存放C库函数头文件所在目录中寻找
经常用在文件头部的被包含的文件称为“标题文件”或“头部文件”,一般以.h为后缀,一般将如下内容放到.h文件中:
- 宏定义
- 结构、联合和枚举声明
- typedef声明
- 外部函数声明
- 全局变量声明
文件包含需要注意:
- 一个#define命令只能指定一个被包含的文件
- 文件包含是可以嵌套的
- 若file1.c中包含文件file2.h,那么在预编译以后就成为一个文件,而不是两个文件。如果file2.h中有全局静态变量,则在file1.c中也有效
3、条件编译
预处理器提供了条件编译功能
3.1、#if命令
含义:如果#if命令后的参数表达式为真,则编译#if到#endif之间的程序段,否则跳过
#if 常数表达式
语句段
#endif
#else的作用是为#if为假时提供另一种选择
#if 常数表达式
语句段
#else
语句段
#endif
#elif指令用来建立一种“如果……或者如果……”阶梯状多重编译操作选择
#if 表达式
语句段
#elif 表达式1
语句段1
#elif 表达式2
语句段2
...
#elif 表达式n
语句段n
#endif
3.2、#ifdef及#ifndef命令
在#if条件编译命令中,需要判断符号常量所定义的具体值。但有时不需要判断具体值,只需要知道这个符号常量是否被定义了,这时使用#ifdef和#ifndef,分别表示“如果有定义”和“如果无定义”
#ifdef一般形式
#ifdef 宏名
语句段
#endif
#ifdef和#else连用
#ifdef 宏名
语句段
#else
语句段1
#endif
#ifndef一般形式
#ifndef 宏名
语句段
#endif
#ifndef和#else连用
#ifndef 宏名
语句段
#else
语句段1
#endif
3.3、#undef命令
#undef命令可以删除事先定义好的宏定义。目的是将宏名局限在需要它们的代码段中。
#undef 宏名
3.4、#line命令
#line命令用于显示__LINE__和__FILE__内容。__LINE__存放当前编译行的行号,__FILE__存放当前编译的文件名。
#line命令一般形式:
#line 行号[“文件名”]
行号:源程序中当前行号
文件名:源文件的名字
3.5、#pragma命令
3.5.1、#pragma命令
#pragma命令的作用是设定编译器的状态,或者指示编译器完成一些特定的动作
#pragma命令的一般形式:
#pragma 参数
参数分为:
- message参数:在编译信息窗口中输出相应的信息
- code_seg参数:设置程序中函数代码存放的代码段
- once参数:保证头文件被编译一次
3.5.2、预定义宏名
ANSI标准说明了以下5个预定义宏名
- __LINE__:当前被编译代码的行号
- __FILE__:当前源程序的文件名称
- __DATE__:当前源程序的创建日期
- __TIME__:当前源程序的创建时间
- __STDC__:用来判断当前编译器是否为标准C。若其值为1,则表示符合标准C,否则不是标准C