C语言中条件编译详解

所属分类: 软件编程 / C 语言 阅读数: 86
收藏 0 赞 0 分享

通常情况,我们想让程序选择性地执行,多会使用分支语句,比如if-else 或者switch-case 等。但有些时候,可能在程序的运行过程中,某个分支根本不会执行。

比如我们要写一个跨平台项目,要求项目既能在Windows下运行,也能在Linux下运行。这个时候,如果我们使用if-else,如下:

Windows 有专有的宏_WIN32,Linux 有专有的宏__linux__

if(_WIN32)
  printf("Windows下执行的代码\n");
else if(__linux__)
  printf("Linux下执行的代码\n");
else
  printf("未知平台不能运行!\n");

这段代码存在两个问题:1、 在Windows下并没有定义__linux__,编译的时候会报错,同样在Linux中也没有定义_WIN32。2、 假定这段程序可以运行,那么在Windows环境下另外两个分支的代码根本不可能运行,同理在Linux下也一样。

处理这种情况我们可以使用条件编译。条件编译,顾名思义,就是根据一定的条件进行选择性的编译,我们要达到的效果,就是在Windows环境下另外两个分支的语句根本不会编译,这样生成的可执行文件中,也不会还有对应语句的机器码,这样既提高了编译效率,同时也减小了可执行文件的体积。

条件编译通常可以用三种方式实现:

1、 #if--#elif--#else--#endif语句实现

通过这种方法实现的代码为:

#if(_WIN32)
  printf("Windows下执行的代码\n");
#elif (__linux__)
  printf("Linux下执行的代码\n");
#else
  printf("未知平台不能运行!\n");
#endif

使用这种方式时需要注意,宏定义为真实#if才会执行,也就是说:

假如有宏定义#define _WIN32 0 这个时候#if是不会执行的。需要定义为#define _WIN32 1才会执行

2、 通过#ifdef--#else--#endif语句实现

通过这种方式实现的代码为

#ifdef(_WIN32)
  printf("Windows下执行的代码\n");
#else
  printf("Linux下执行的代码\n");
#endif

这种方法下只需要定义了_WIN32就可以,没有必要为真,也就是说

如果有宏定义#define _WIN32 0 上面#ifdef语句也是可以执行的,甚至#define _WIN32 上面的#ifdef也可以运行

当然也可以加入第一种方法中的#elif语句

#ifdef(_WIN32)
  printf("Windows下执行的代码\n");
#elif (__linux__)
  printf("Linux下执行的代码\n");
#else
  printf("未知平台不能运行!\n");
#end

但是需要注意的是,这种情况下,要想#elif语句执行__linux__的值必须为真!(同时没有定义_WIN32)

3、 使用#ifndef语句,这种情况类似第二种,ifndef就是如果没有定义宏,就执行。

在gcc编译工具中

我们可以使用-D选项,动态地定义程序所需要的宏

比如我们可以这样编译 gcc test.c -o test -D _WIN32      这样程序就可以在Windows下运行了(当然,实际情况是在Windows环境下,_WIN32已经被定义) gcc中的-D选项会默认将宏定义为1,如果要定义为其他的值使用等于号如:-D _WIN32=0      

很多的时候,尤其是实际的项目中,我们会使用cmake工具来构建自己的程序。

在cmake中

我们可以在CMakeLists.txt中写入ADD_DEIFNITIONS(-D _WIN32)来添加程序运行时用到的宏。但是这样,一旦我们需要修改使用的宏,就要修改CMakeLists.txt文件,会很麻烦。

这时我们可以这样做:

在CMakeLists.txt中写入

IF(ENVIRO)
 ADD_DEFINITIONS(-D _WIN32)
ENDIF(ENVIRO)

这样,我们可以在使用cmake命令的时候加入-D选项,定义ENVIRO 命令如下

cmake -D ENVIRO=1,或者 cmake -D ENVIRO=ON

如果要取消这个定义可以使用: cmake -D ENVIRO=OFF 或 cmake -D ENVIRO=0 或者cmake -U ENVIRO

就写到这里了,希望对你有帮助。。水平有限,有错误的地方还请谅解,并诚邀指正。。

更多精彩内容其他人还在看

用标准c++实现string与各种类型之间的转换

这个类在头文件中定义, < sstream>库定义了三种类:istringstream、ostringstream和stringstream,分别用来进行流的输入、输出和输入输出操作。另外,每个类都有一个对应的宽字符集版本
收藏 0 赞 0 分享

C++如何通过ostringstream实现任意类型转string

再使用整型转string的时候感觉有点棘手,因为itoa不是标准C里面的,而且即便是有itoa,其他类型转string不是很方便。后来去网上找了一下,发现有一个好方法
收藏 0 赞 0 分享

C/C++指针小结

要搞清一个指针需要搞清指针的四方面的内容:指针的类型,指针所指向的类型,指针的值或者叫指针所指向的内存区,还有指针本身所占据的内存区
收藏 0 赞 0 分享

C++ 类的静态成员深入解析

在C++中类的静态成员变量和静态成员函数是个容易出错的地方,本文先通过几个例子来总结静态成员变量和成员函数使用规则,再给出一个实例来加深印象
收藏 0 赞 0 分享

C++类的静态成员初始化详细讲解

通常静态数据成员在类声明中声明,在包含类方法的文件中初始化.初始化时使用作用域操作符来指出静态成员所属的类.但如果静态成员是整型或是枚举型const,则可以在类声明中初始化
收藏 0 赞 0 分享

C++类静态成员与类静态成员函数详解

静态成员不可在类体内进行赋值,因为它是被所有该类的对象所共享的。你在一个对象里给它赋值,其他对象里的该成员也会发生变化。为了避免混乱,所以不可在类体内进行赋值
收藏 0 赞 0 分享

C++中的friend友元函数详细解析

友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类。友元函数的特点是能够访问类中的私有成员的非成员函数。友元函数从语法上看,它与普通函数一样,即在定义上和调用上与普通函数一样
收藏 0 赞 0 分享

static全局变量与普通的全局变量的区别详细解析

以下是对static全局变量与普通的全局变量的区别进行了详细的分析介绍,需要的朋友可以过来参考下,希望对大家有所帮助
收藏 0 赞 0 分享

C++ explicit关键字的应用方法详细讲解

C++ explicit关键字用来修饰类的构造函数,表明该构造函数是显式的,既然有"显式"那么必然就有"隐式",那么什么是显示而什么又是隐式的呢?下面就让我们一起来看看这方面的知识吧
收藏 0 赞 0 分享

教你5分钟轻松搞定内存字节对齐

随便google一下,人家就可以跟你解释的,一大堆的道理,我们没怎么多时间,讨论为何要对齐.直入主题,怎么判断内存对齐规则,sizeof的结果怎么来的,请牢记以下3条原则
收藏 0 赞 0 分享
查看更多