预处理指令是以#号开头的代码行。#号必须是该行除了任何空白字符外的第一个字符。#后是指令关键字,在关键字和#号之间允许存在任意个数的空白字符。整行语句构成了一条预处理指令,该指令将在编译器进行编译之前对源代码做某些转换。下面是部分预处理指令:
#空指令,无任何效果
#include包含一个源代码文件
#define定义宏
#undef取消已定义的宏
#if如果给定条件为真,则编译下面代码
#ifdef如果宏已经定义,则编译下面代码
#ifndef如果宏没有定义,则编译下面代码
#elif如果前面的#if给定条件不为真,当前条件为真,则编译下面代码
#endif结束一个#if……#else条件编译块
#error停止编译并显示错误信息
今天主要是对 #ifdef(#ifndef),#else,#endif,#if,#elif等预处理条件编译的命令进行总结,加深自己的记忆。
1. 在头文件中使用频繁的#ifndef #define...........#endif这三条指令。
头件的中的#ifndef(if not define),它的意思是如果没有定义该指令后面的变量,则执行下面的代码。比如你有两个C文件,这两个C文件都include了同一个头文件。而编译时,这两个C文件要一同编译成一个可运行文件,于是问题来了,大量的声明冲突。如果将头文件中的内容放在#ifndef和#endif中,则当一个C文件预处理之后就定义了该宏名,另一个C文件调用的时候就因为被定义而无法进入头文件的内容,就不会出现声明的冲突了。
有人可能会有这样一个问题:如果另一个C文件希望调用头文件中的一个函数,都进不了头文件,还怎么能调用那个函数呢?
我的理解是这样的:当第一个C文件调用了那个头文件之后,编译器就会将该头文件进行编译,当下一个C文件调用时,包含该头文件就相当于去寻找已经编译好的代替那个头文件的编译文件,就可以调用里面的函数了。类似于#define A 100,当使用A时,就是使用100的值。
一般格式是这样的:
#ifndef __DELAY_H__
#define __DELAY_H__
......
#endif /* __DELAY_H__ */
在理论上来说指令后面的标识可以是自由命名的,但每个头文件的这个“标识”都应该是唯一的。标识的命名规则一般是头文件名全大写,前后加双下划线,并把文件名中的“.”也变成下划线,如:delay.h的标识为__DELAY_H__。
2.#ifdef与#ifndef的比较
#ifdef就是if define,意思是其后面的标识如果已经定义了,则执行它下面的代码。反之,则不执行。
#ifndef就是if not define,意思是其后面的标识如果没有被定义,则执行它下面的代码。反之,则不执行。
举例说明:
#define YJ
#ifdef YJ
<Code1>
#endif
#ifndef YJ
<Code2>
#endif
很显然,YJ标识已经被定义了,预编译Code1。
3. #if #elif #else #endif的用法
#if <常量表达式> 当常量表达式为真时,执行下面的代码;
#elif <常量表达式> 综合了#else #if指令的作用,即当前面#if表达式不为真时,而#elif表达式为真时,执行下面的代码;
#else <常量表达式> 表示当前一个#if指令表达式不为真时,执行#else下面的代码。
#endif 结束一个#if的预处理的指令。
举例说明:
#define YJ 1
#define ZQ 0
#if ZQ
<Code1>
#elif YJ
<Code2>
#else
<Code3>
#endif
很显然,最后会预编译Code2。
4.其他一些标准指令
#error指令将使编译器显示一条错误信息,然后停止编译。
#line指令可以改变编译器用来指出警告和错误信息的文件号和行号。
#pragma指令没有正式的定义。编译器可以自定义其用途。典型的用法是禁止或允许某些烦人的警告信息。