深入浅析C/C++ 的条件编译

 更新时间:2022年04月24日 10:21:06   作者:五毛变向.  
条件编译是指预处理的时候根据条件编译的指令有条件的选择源程序中的一部分代码送给编译器进行编译,进行有选择性的操作,防止宏替换的内容重复包含,这篇文章主要介绍了C/C++ 的条件编译,需要的朋友可以参考下

1.条件编译的时机

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

那必然是经历以下这四步

  • 处理:宏替换,头文件的展开,去注释,条件编译
  • 编译:将预处理后的源文件转换为汇编语言文件,只编译源文件,不编译头文件,头文件在刚刚预处理阶段已经展开。
  • 汇编:虽然叫做汇编,但是不是转变为汇编代码,而是将刚刚的汇编语言文件转换为机器码,也就是二进制文件。
  • 链接:将生成的二进制代码与库函数以及其他目标文件,通过链接器链接起来形成可执行文件的过程。

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

2.条件编译的作用

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

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

常见条件编译指令

3.#if #else #endif

#if 表达式
 
// code
#else
#endif

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

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

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

4.#ifndef #define #endif

#ifdef 标识符
#define 标识符 替换列表
 
// code
#endef
  • 一般用于检测程序中是否已经定义了名字为某标识符的宏,如果没有定义该宏,则定义该宏,并选中从 #define 开始到 #endif 之间的程序段;
  • 如果已定义,则不再重复定义该符号,且相应程序段不被选中。

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

红色框框是每个函数都有的,就是主函数栈帧开辟和销毁的过程,再看中间好家伙啥都没有,再次印证了,我们说的如果没有定义该宏,则定义该宏,并选中从 #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 被选中编译。

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已定义,则删除其定义,并选中相应的程序段。

到此这篇关于深入浅析C/C++ 的条件编译的文章就介绍到这了,更多相关c++条件编译内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:

相关文章

  • 探讨C语言的那些小秘密之断言

    探讨C语言的那些小秘密之断言

    我尽可能的把我所理解的断言的使用讲解清楚,希望我在此所讲的断言能够对你有所帮助,让你以后能够在代码中灵活使用断言
    2013-09-09
  • C++实现栈的操作(push和pop)

    C++实现栈的操作(push和pop)

    这篇文章主要介绍了C++实现栈的操作(push和pop),具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-07-07
  • C++ Queue队列类模版实例详解

    C++ Queue队列类模版实例详解

    这篇文章主要为大家详细介绍C++ Queue队列类模版实例,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-02-02
  • c++11新特性多线程操作实战

    c++11新特性多线程操作实战

    这篇文章主要介绍了c++11新特性多线程操作实战,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • C语言数据结构之模式匹配字符串定位问题

    C语言数据结构之模式匹配字符串定位问题

    这篇文章主要介绍了C语言数据结构之模式匹配字符串定位问题的相关资料,希望通过本文能帮助到大家,让大家理解这部分内容,需要的朋友可以参考下
    2017-10-10
  • 浅谈C++继承中的名字查找

    浅谈C++继承中的名字查找

    下面小编就为大家带来一篇浅谈C++继承中的名字查找。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-01-01
  • 利用C语言实现三子棋(井字棋)小游戏

    利用C语言实现三子棋(井字棋)小游戏

    这篇文章主要为大家详细介绍了利用C语言实现三子棋小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • C++解析特殊符号tab和换行符号详情

    C++解析特殊符号tab和换行符号详情

    这篇文章主要给大家介绍的是C++解析一些特殊符号tab、换行符号的一些相关资料,需要的小伙伴可以参考下面文章的具体内容
    2021-09-09
  • C++函数返回值为对象时,构造析构函数的执行细节

    C++函数返回值为对象时,构造析构函数的执行细节

    C++函数返回值为对象时,构造析构函数的执行细节,需要的朋友,可以参考下
    2013-02-02
  • 基于atoi()与itoa()函数的内部实现方法详解

    基于atoi()与itoa()函数的内部实现方法详解

    本篇文章是对atoi()与itoa()函数的内部实现方法进行了详细的分析介绍,需要的朋友参考下
    2013-05-05

最新评论