C语言#if,#ifdef,#ifndef条件编译用法汇总

条件编译是根据实际定义宏(某类条件)进行代码静态编译的手段。可根据表达式的值或某个特定宏是否被定义来确定编译条件。

最常见的条件编译是防止重复包含头文件的宏,几乎所有头文件都要采用下述的方法编辑以防止被重复包含,形式跟下面代码类似:

#ifndef ABCD_H
#define ABCD_H

// ... some declaration codes

#endif // #ifndef ABCD_H

在C文件中通常有如下类似的定义:

#ifdef _DEBUG

// ... do some operations

#endif

#ifdef _WIN32

// ... use  Win32 API

#endif

常见的条件编译指令

1、#if:如果条件为真,则执行相应的操作。
2、#elif:类似于 elseif 的用法,当前面条件为假,再判断该条件是否为真,如果是真,则执行相应操作。
3、#else:如果前面所有条件均为假,则执行相应操作。
4、#ifdef:如果该宏已定义,则执行相应操作。
5、#ifndef:如果该宏没有定义,则执行相应操作。
6、#endif :结束对应的条件编译指令。(不能省略)
defined :与#if, #elif配合使用,判断某个宏是否被定义

#if,#elif,#else与#endif

#if 指令很像C语言中的 if 语句。#if 后面跟常量表达式,如果表达式为非0,则表达式为真,执行 #if 与 #endif 中间的所有C代码;如果表达式为0,则表达式为假,中间的代码不参与编译。

#if可与常量表达式配合使用。常用格式如下:

#if 常量表达式1
// ... some codes
#elif 常量表达式2
// ... other codes
#elif 常量表达式3
// ...
...
#else
// ... statement
#endif

上面的#if、#elif、#else可以与条件判断语句的if elseif else联系起来理解,同样地,#elif、#else也不是一定需要存在。
常量表达式可以是包含宏、算术运算、逻辑运算等等的合法C常量表达式,如果常量表达式为一个未定义的宏, 那么它的值被视为0。

#if MACRO_NON_DEFINED // 等价于

#if 0

在判断某个宏是否被定义时,应当避免使用#if,因为该宏的值可能就是被定义为0。而应当使用#ifdef或#ifndef。

下面举几个例子:
例1:

#if 0
//代码1
#endif

上面这种用法,相当于#if 0 和 #endif之间的代码被注释掉了,一般在IDE环境中会显示灰色。如果需要这段代码参与编译,那么把#if 0改为#if 1即可。但这种用法最好只是调试阶段临时用,没有太大的现实意义,因为这就跟/* */注释符号类似了。

例2:

#define FUNCTION 0

#if FUNCTION
//代码1
#endif

上面这种用法相对常用,即FUNCTION宏定义为0或者1,决定了#if FUNCTION和#endif之间的代码是否参与编译。
对FUNCTION的宏定义可以放在某个配置用的头文件中,便于集中管控。

例3:

#define FUNCTION 0

#if FUNCTION
//代码1
#else
//代码2
#endif

与例2类似,FUNCTION宏定义为0或者1,FUNCTION为1,则#if FUNCTION和#else之间的代码1参与编译,FUNCTION为0,则#else和#endif之间的代码2参与编译。

例4:

#define FUNCTION 0

#if (FUNCTION == 0)
//代码1
#elif (FUNCTION == 1)
//代码2
#elif (FUNCTION == 2)
//代码3
#endif

FUNCTION宏定义为0或者1或者2,FUNCTION为0,则代码1参与编译,FUNCTION为1,则代码2参与编译,FUNCTION为2,则代码3参与编译。
由于0,1,2不能直观理解,我们还能对0,1,2进行一层宏定义,以增加代码可阅读性,比如:

#define FUN_A 0
#define FUN_B 1
#define FUN_C 2

#define FUNCTION FUN_A

#if (FUNCTION == FUN_A)
//代码1
#elif (FUNCTION == FUN_B)
//代码2
#elif (FUNCTION == FUN_C)
//代码3
#endif

例5:

#define FUN_A 1
#define FUN_B 1

#if (FUN_A && FUN_B)
//代码1
#endif

只有当FUN_A和FUN_B同时定义为1时,代码1才参与编译,否则代码1不参与编译。

例6:

#define FUNCTION 1

#if (FUNCTION < 5)
//代码1
#endif

只有当FUNCTION的定义小于5时,代码1才参与编译,否则代码1不参与编译。

#ifdef,#ifndef,#else与#endif

条件编译中相对常用的预编译指令。模式如下:

#ifdef ABC
// ... codes while definded ABC
#elif (CODE_VERSION > 2)
// ... codes while CODE_VERSION > 2
#else
// ... remained cases
#endif // #ifdef ABC

#ifdef用于判断某个宏是否定义,和#ifndef功能正好相反,二者仅支持判断单个宏是否已经定义,上面例子中二者可以互换。
如果不需要多条件预编译的话,上面例子中的#elif和#else均可以不写。

#ifdef 由于只能判定单个宏是否定义,那么自然没有#if 后面可以判定一个表达式那么多花样,所以就不能举大量的例子了。

#if defined

defined用来测试某个宏是否被定义。defined(name): 若宏被定义,则返回1,否则返回0。
它与#if、#elif、#else结合使用来判断宏是否被定义,乍一看好像它显得多余, 因为已经有了#ifdef和#ifndef。defined可用于在一条判断语句中声明多个判别条件;#ifdef和#ifndef则仅支持判断一个宏是否定义。

类似:

#if defined(VAX) && defined(UNIX) && !defined(DEBUG) 

当然,如果是判断单个条件,#if defined和#ifdef没有啥差别。

#if defined(VAX)#ifdef VAX

#if !defined

#if !defined与#ifndef类似,都是用来判断宏没有被定义。
区别在于#if !defined可以判断多个(类似前面的#if defined)。

#if !defined(VAX)#ifndef VAX

这两者效果一样。

#if !defined的本质还是#if defined,所以它们可以组合

#if defined(VAX) && defined(UNIX) && !defined(DEBUG) 

这个例子就是当VAX和UNIX都定义了,并且DEBUG没有被定义的情况下,则条件成立。