打印
[经验分享]

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

[复制链接]
4723|57
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
jackcat|  楼主 | 2023-10-23 17:00 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
条件编译是根据实际定义宏(某类条件)进行代码静态编译的手段。可根据表达式的值或某个特定宏是否被定义来确定编译条件。

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

#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没有被定义的情况下,则条件成立。

原文链接:https://blog.csdn.net/weixin_44788542/article/details/130922902

使用特权

评论回复
沙发
eefas| | 2023-11-5 14:40 | 只看该作者
这些宏只能在当前源文件的范围内使用。如果需要在不同的源文件中使用不同的代码段,则需要使用其他方式来实现。

使用特权

评论回复
板凳
sheflynn| | 2023-11-5 15:13 | 只看该作者
#if,#ifdef,#ifndef 是预处理器指令

使用特权

评论回复
地板
pl202| | 2023-11-5 15:49 | 只看该作者
使用这些指令可以提供更灵活的编译控制,使得程序可以根据特定的编译环境、编译器选项或者定义了某些宏来选择性地编译和执行代码。

使用特权

评论回复
5
geraldbetty| | 2023-11-5 16:33 | 只看该作者
在使用C语言中的#if、#ifdef和#ifndef指令进行条件编译时,需要注意条件判断

使用特权

评论回复
6
phoenixwhite| | 2023-11-5 17:14 | 只看该作者
#if: 这个指令后面跟着一个表达式,如果这个表达式的值为真(非零),那么紧跟在这个指令后面的代码会被编译到最终的程序中。如果这个表达式的值为假(零),那么紧跟在这个指令后面的代码会被忽略。

使用特权

评论回复
7
febgxu| | 2023-11-5 17:48 | 只看该作者
在编写跨平台代码时,需要特别注意条件编译的使用,以确保在不同平台上都能正确运行。

使用特权

评论回复
8
burgessmaggie| | 2023-11-5 18:30 | 只看该作者
注意使用#define定义宏名称时,宏名称大小写敏感,定义的位置也很重要,需要放在#include语句之后。

使用特权

评论回复
9
pixhw| | 2023-11-5 20:10 | 只看该作者
如果某个条件编译指令的条件始终为假(零),那么紧跟在其后的代码块将***不会被编译。为了避免这种情况,可以在条件编译指令之前添加一条注释,说明为什么这个条件编译指令是必要的

使用特权

评论回复
10
olivem55arlowe| | 2023-11-5 20:56 | 只看该作者
只在对应的条件满足时才会编译。              

使用特权

评论回复
11
kkzz| | 2023-11-5 21:31 | 只看该作者
#if, #ifdef, #ifndef定义的条件编译符号只在当前源文件中有效。

使用特权

评论回复
12
backlugin| | 2023-11-5 22:02 | 只看该作者
不同的编译器和操作系统可能对预编译指令的支持有所不同。在使用时,请测试代码在目标编译器和操作系统上的编译和运行情况。

使用特权

评论回复
13
robertesth| | 2023-11-5 22:35 | 只看该作者
使用条件编译时,请保持代码简洁。避免在条件编译块中编写过多的代码

使用特权

评论回复
14
benjaminka| | 2023-11-6 19:41 | 只看该作者
条件编译可以嵌套使用,以扩展条件编译的范围

使用特权

评论回复
15
cemaj| | 2023-11-7 16:38 | 只看该作者
在使用#ifdef和#ifndef时,要确保你正在检查的宏名不会与其他代码中的宏名冲突。

使用特权

评论回复
16
sdlls| | 2023-11-7 17:22 | 只看该作者
#ifdef: 这个指令后面跟着一个宏名,如果这个宏已经被定义了,那么紧跟在这个指令后面的代码会被编译到最终的程序中。如果这个宏还没有被定义,那么紧跟在这个指令后面的代码会被忽略。

使用特权

评论回复
17
hudi008| | 2023-11-7 18:24 | 只看该作者
预编译指令通常放在要编译的代码之前,以便编译器根据指令进行编译。在使用时,请确保预编译指令位于要编译的代码之前。

使用特权

评论回复
18
cashrwood| | 2023-11-8 11:39 | 只看该作者
在使用#if时,要注意避免出现#if 0这样的代码,因为这会导致编译器浪费资源去检查一个***为假的表达式。

使用特权

评论回复
19
hilahope| | 2023-11-8 12:46 | 只看该作者
#if、#ifdef和#ifndef是条件编译指令,用于根据预处理器定义的宏来控制代码的编译。

使用特权

评论回复
20
backlugin| | 2023-11-8 13:02 | 只看该作者
过度使用条件编译可能会导致代码难以阅读和维护。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

7

主题

1525

帖子

0

粉丝