快速搞定C/C++ 的条件编译

点击蓝字

859fbe1d6b6f227757915dacdf0f207f.png

关注我们

1、条件编译的时机

我们都知道vscode其实是一个编辑器,你要在上面跑C或者C++你需要配置编译器,拿编译器是怎样吧一个文本文件变成一个可执行文件的呢?

那必然是经历以下这四步

  • 预处理:宏替换,头文件的展开,去注释,条件编译

  • 编译:将预处理后的源文件转换为汇编语言文件,只编译源文件,不编译头文件,头文件在刚刚预处理阶段已经展开。

  • 汇编:虽然叫做汇编,但是不是转变为汇编代码,而是将刚刚的汇编语言文件转换为机器码,也就是二进制文件。

  • 链接:将生成的二进制代码与库函数以及其他目标文件,通过链接器链接起来形成可执行文件的过程。

分析了以上过程由此可以很清晰的得出这个结论,条件编译是在预处理的时候发生的。

2、条件编译的作用

条件编译是指预处理的时候根据条件编译的指令有条件的选择源程序中的一部分代码送给编译器进行编译,进行有选择性的操作,防止宏替换的内容重复包含。

常见的条件编译指令如下:

14f1d8f718bf0c66a5ff43dd233be9e3.png

3、#if   #else   #endif

#if 表达式


// code


#else


// code


#endif

如果表达式为真则#if后程序段被调用

5b02a65fc694040d26c8af620f9f9f27.png

明显发现第一段的色段跟第二段的色段都不一样!肯定是第一句输出了!

ada54334c0add058f6c2be5333a6ad8a.png

可以看到他直接call调用的就是标准命名空间下的operator类里面的函数,其实也就是 << 输出

4、#ifndef   #define   #endif

#ifdef 标识符
#define 标识符 替换列表


// code


#endef
  • 一般用于检测程序中是否已经定义了名字为某标识符的宏,如果没有定义该宏,则定义该宏,并选中从 #define 开始到 #endif 之间的程序段;

  • 如果已定义,则不再重复定义该符号,且相应程序段不被选中。

我们都知道NULL在C中是一个宏,宏有时也会引起不必要的问题在C++11中则有了nullptr,所以这块显示是已经被宏过了,所有不执行#define 到#endef的程序段所以看起来是灰色的。

6b32c44c76e31f85a020974d369ad9a8.png

5c98ba6eaeae8ad3406da91c43790fba.png

01b7c886f849e6aa3b878b180bceeb89.jpeg

红色框框是每个函数都有的,就是主函数栈帧开辟和销毁的过程,再看中间好家伙啥都没有,再次印证了,我们说的 如果没有定义该宏,则定义该宏,并选中从 #define 开始到 #endif 之间的程序段;如果已定义,则不再重复定义该符号,且相应程序段不被选中。

该条件编译指令更重要的一个应用是防止头文件重复包含。

如果 f.c 源文件中包含 f1.h 和 f2.h 两个头文件,而 f1.h 头文件及 f2.h 头文件中均包含 f3.h 头文件,则 f.c 源文件因为包含了 f1.h 和 f2.h 两个头文件,所以中重复包含 f3.h 头文件。可采用条件编译指令,来避免头文件的重复包含问题。

#ifndef _HEADNAME_H_


#define _HEADNAME_H_


    //头文件内容


#endif
  • 当该头文件第一次被包含时,由于没检测到该头文件名对应的宏名,则定义该头文件名对应的宏,其值为该系统默认。并且,该条件编译指令选中 #endif 之前的头文件内容;

  • 如果该头文件再次被包含时,由于检测到已存在以该头文件名对应的宏名,则忽略该条件编译指令之间的所有代码,从而避免了重复包含。

5、#if   #elif   #else   #endif

#if 条件表达式1


    // code1


#elif 条件表达式2


    //code 2


#else


    //code 3


#endif
  • 功能为:先判断条件1的值,如果为真,则程序段 1 被选中编译;

  • 如果为假,而条件表达式 2 的值为真,则程序段 2 被选中编译;

  • 其他情况,程序段 3 被选中编译。

33f5398a237efa2857e1a7dc1e833bc1.png

6、#ifdef   #endif

#ifdef 标识符


//code


#endif

如果检测到已定义该标识符,则选择执行相应程序段被选中编译;否则,该程序段会被忽略。

#include <iostream>
using namespace std;
#define PI 3.14
int main() {
#ifdef PI 
#undef PI
cout << "PI 已经被取消宏" << endl;
#endif
}

如果检测到符号 PI 已定义,则删除其定义,并选中相应的程序段。

2d541887aa642a7df02a349171828da1.png

c5a2f2bb63a524d723ba4613ea1f40c1.png

*声明:本文于网络整理,版权归原作者所有,如来源信息有误或侵犯权益,请联系我们删除或授权事宜。

39bd05c72ce315f9c8807b80adb0e3ef.png

e18e219b8e123db3299e9d6a91fb2154.gif

戳“阅读原文”我们一起进步

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值