预处理器在源代码编译前对其进行一些文本性质的操作, 主要任务包括删除注释, 插入被 #include
指令包含的文件的内容, 定义和替换由 #define
指令定义的符号以及确定代码的部分内容是否应该根据一些条件编译指令进行编译.
#define
指令
#define
指令主要有两种用法:
- 定义常量:
#define name stuff
当源代码中出现 name 符号时都会被原封不动的替换为 stuff. - 宏:
#define name(parameter1, parameter2, ...) stuff
当源代码中出现 name(parameter1, parameter2, …) 时都会被替换为 stuff, 并且 stuff 中出现的 parameter 符号都被替换为括号内的值.
比如:
- 定义常量:
#define MAX(a, b) ((a) > (b) ? (a) : (b))
MAX(2, 4); // 等价与((2) > (4) ? (2) : (b))
使用 #define
指令有以下几点需要注意:
(1) 不要在定义或宏的最后加 ; 来表示语句的结束.
(2) 在宏定义时为每一个宏参数以及 stuff 的最外围加上括号.
(3) #define
内部可以嵌套 #define
, 但是不能递归嵌套.
(4) 当宏参数在宏定义中出现次数超过一次时要格外注意每次出现是宏参数的值有没有发生潜在的变化.
(4) #define
的名字统一要大写.
#undef
指令
#undef
指令用于解除#define
指令定义的符号或宏.
#define PI 3.1415 // 定义PI
#undef PI // 使PI定义失效
#include
指令
#include
用于将某个文件包含到当前文件. 主要用法有三种:
#include <headfile.h> // 到系统目录搜索headfile.h
#include "headfile.h" // 先到当前工作目录搜索headfile.h, 未找到的话再去系统目录
#include "/use/test/headfile.h" // 直接去指定的目录搜索headfile.h
- 条件编译指令:
#ifdef
#ifndef
#else
#elif
#endif
#ifdef
表示如果已经定义了#ifdef
后的符号, 则执行#ifdef
后的命令语句直到遇到#else
或#endif
. 注意:#ifdef name
等价与#if defined(name)
#ifndef
表示如果没有定义了#ifndef
后的符号, 则执行#ifndef
后的命令语句直到遇到#else
或#endif
. 注意:#ifndef name
等价与#if !defined(name)
#else
#elif
和#endif
用于组合使用.
常用的结构有:
// 组合1
#ifdef name // 等价与 #if define(name)
...
#else
...
#endif
// 组合2
#ifdef name
...
#elif
...
#else
...
#endif
// 组合3
#ifndef name // 等价与 #if !define(name)
...
#else
...
#endif
// 组合4
#ifndef name
...
#endif
#error
指令
#error
用于使预处理器发出一条错误信息, 比如:
#define PI 3.1415
#ifndef PI
#error Not define PI
#endif
当未定义PI时, 预处理器会发出Not define PI信息, 并停止预处理.
#line
指令
#line
用于重置当前行号和文件名.
#line 50 // 重置当前行号为50
#line 100 "test.c" // 重置当前文件名为test.c
#
运算符
#
用于将字符串中的参数名视为宏参数. 比如:
// 字符串中参数名a被视为字符
#define PRINTSQUARE(a) printf("The square of a is: %d\n", ((a) * (a)))
PRINTSQUARE(3); // 输出:The square of a is: 9
// 字符串中参数名a被视为宏参数
#define PRINTSQUARE(a) printf("The square of "#a" is: %d\n", ((a) * (a)))
PRINTSQUARE(3); // 输出:The square of 3 is: 9
##
运算符
##
用于将两个符号合成一个符号. 比如:
#define XNAME(n) x##n
int XNAME(1) = 0; // 等价于: int x1 = 0;
int XNAME(2) = 1; // 等价于: int x2 = 1;
\
连接符
\
用于连接多行预处理语句. 比如
#define MAX(a, b) ((a) > (b) ? \
(a) : (b))
- 预定义宏
__DATE__
预定义器处理时的日期__FILE__
当前源代码文件名__LINE__
当前行号__TIME__
预定义器处理的时间__STDC__
如果编译器遵循ANSIC, 其值为1, 否则为定义