C语言:条件编译
假如现在要开发一个C语言程序,让它输出红色的文字,并且要求跨平台,在 Windows 和 Linux 下都能运行,怎么办呢?
这个程序的难点在于,不同平台下控制文字颜色的代码不一样,我们必须要能够识别出不同的平台。
Windows 有专有的宏_WIN32
,Linux 有专有的宏__linux__
,以现有的知识,我们很容易就想到了 if else,请看下面的代码:
- #include <stdio.h>
- int main(){
- if(_WIN32){
- system("color 0c");
- printf("http://c.biancheng.net\n");
- }else if(__linux__){
- printf("\033[22;31mhttp://c.biancheng.net\n\033[22;30m");
- }else{
- printf("http://c.biancheng.net\n");
- }
- return 0;
- }
但这段代码是错误的,在 Windows 下提示 __linux__ 是未定义的标识符,在 Linux 下提示 _Win32 是未定义的标识符。对上面的代码进行改进:
- #include <stdio.h>
- int main(){
- #if _WIN32
- system("color 0c");
- printf("http://c.biancheng.net\n");
- #elif __linux__
- printf("\033[22;31mhttp://c.biancheng.net\n\033[22;30m");
- #else
- printf("http://c.biancheng.net\n");
- #endif
- return 0;
- }
#if、#elif、#else 和 #endif 都是预处理命令,整段代码的意思是:如果宏 _WIN32 的值为真,就保留第 4、5 行代码,删除第 7、9 行代码;如果宏 __linux__ 的值为真,就保留第 7 行代码;如果所有的宏都为假,就保留第 9 行代码。
这些操作都是在预处理阶段完成的,多余的代码以及所有的宏都不会参与编译,不仅保证了代码的正确性,还减小了编译后文件的体积。
这种能够根据不同情况编译不同代码、产生不同目标文件的机制,称为条件编译。条件编译是预处理程序的功能,不是编译器的功能。
条件编译需要多个预处理命令的支持,下面一一讲解。
#if 的用法
#if 用法的一般格式为:
#if 整型常量表达式1
程序段1
#elif 整型常量表达式2
程序段2
#elif 整型常量表达式3
程序段3
#else
程序段4
#endif
它的意思是:如常“表达式1”的值为真(非0),就对“程序段1”进行编译,否则就计算“表达式2”,结果为真的话就对“程序段2”进行编译,为假的话就继续往下匹配,直到遇到值为真的表达式,或者遇到 #else。这一点和 if else 非常类似。
需要注意的是,#if 命令要求判断条件为“整型常量表达式”,也就是说,表达式中不能包含变量,而且结果必须是整数;而 if 后面的表达式没有限制,只要符合语法就行。这是 #if 和 if 的一个重要区别。
#elif 和 #else 也可以省略,如下所示:
- #include <stdio.h>
- int main(){
- #if _WIN32
- printf("This is Windows!\n");
- #else
- printf("Unknown platform!\n");
- #endif
- #if __linux__
- printf("This is Linux!\n");
- #endif
- return 0;
- }
#ifdef 的用法
#ifdef 用法的一般格式为:
#ifdef 宏名
程序段1
#else
程序段2
#endif
它的意思是,如果当前的宏已被定义过,则对“程序段1”进行编译,否则对“程序段2”进行编译。
也可以省略 #else:
#ifdef 宏名
程序段
#endif
VS/VC 有两种编译模式,Debug 和 Release。在学习过程中,我们通常使用 Debug 模式,这样便于程序的调试;而最终发布的程序,要使用 Release 模式,这样编译器会进行很多优化,提高程序运行效率,删除冗余信息。
为了能够清楚地看到当前程序的编译模式,我们不妨在程序中增加提示,请看下面的代码:
- #include <stdio.h>
- #include <stdlib.h>
- int main(){
- #ifdef _DEBUG
- printf("正在使用 Debug 模式编译程序...\n");
- #else
- printf("正在使用 Release 模式编译程序...\n");
- #endif
- system("pause");
- return 0;
- }
当以 Debug 模式编译程序时,宏 _DEBUG 会被定义,预处器会保留第 5 行代码,删除第 7 行代码。反之会删除第 5 行,保留第 7 行。
#ifndef 的用法
#ifndef 用法的一般格式为:
#ifndef 宏名
程序段1
#else
程序段2
#endif
与 #ifdef 相比,仅仅是将 #ifdef 改为了 #ifndef。它的意思是,如果当前的宏未被定义,则对“程序段1”进行编译,否则对“程序段2”进行编译,这与 #ifdef 的功能正好相反。
三者之间的区别
最后需要注意的是,#if 后面跟的是“整型常量表达式”,而 #ifdef 和 #ifndef 后面跟的只能是一个宏名,不能是其他的。
例如,下面的形式只能用于 #if:
- #include <stdio.h>
- #define NUM 10
- int main(){
- #if NUM == 10 || NUM == 20
- printf("NUM: %d\n", NUM);
- #else
- printf("NUM Error\n");
- #endif
- return 0;
- }
运行结果:
NUM: 10
再如,两个宏都存在时编译代码A,否则编译代码B:
- #include <stdio.h>
- #define NUM1 10
- #define NUM2 20
- int main(){
- #if (defined NUM1 && defined NUM2)
- //代码A
- printf("NUM1: %d, NUM2: %d\n", NUM1, NUM2);
- #else
- //代码B
- printf("Error\n");
- #endif
- return 0;
- }
运行结果:
NUM1: 10, NUM2: 20
#ifdef 可以认为是 #if defined 的缩写。
C语言:条件编译的更多相关文章
- (五)c语言条件编译#ifdef与#if defined
c语言条件编译#ifdef与#if defined defined NAME是用来判断NAME是否被定义了(被用define定义了). #ifdef NAME == #if defined(NAME) ...
- c语言条件编译#ifdef与#if defined
c语言条件编译#ifdef与#if defined c语言条件编译#ifdef与#if defined 摘自:https://www.cnblogs.com/zhangshenghui/p/566 ...
- c语言条件编译和预编译
转自http://www.cnblogs.com/rusty/archive/2011/03/27/1996806.html 一.C语言由源代码生成的各阶段如下: C源程序->编译预处理-> ...
- C语言条件编译
使用与平台有关的C语言函数,可能会使得程序不具有可移植性.比如Socket编程.多线程编程等是与平台有关的. 若想将程序做成平台无关的就需要用到与平台相关的条件编译. 下面转自:http://blog ...
- C语言条件编译及编译预处理阶段(转)
一.C语言由源代码生成的各阶段如下: C源程序->编译预处理->编译->优化程序->汇编程序->链接程序->可执行文件 其中 编译预处理阶段,读取c源程序,对其中的 ...
- 【转】C语言条件编译及编译预处理阶段
原文: http://www.cnblogs.com/rusty/archive/2011/03/27/1996806.html 1. 宏定义(宏代换,宏替换,宏: 宏定义是C语言提供的3中预处理功能 ...
- C语言条件编译(#if,#ifdef,#ifndef,#endif,#else,#elif)
1.条件编译介绍 条件编译(conditional compiling)命令指定预处理器依据特定的条件来判断保留或删除某段源代码.例如,可以使用条件编译让源代码适用于不同的目标系统,而不需要管理该源代 ...
- 条件编译,C语言条件编译详解
条件编译是指预处理器根据条件编译指令,有条件地选择源程序代码中的一部分代码作为输出,送给编译器进行编译.主要是为了有选择性地执行相应操作,防止宏替换内容(如文件等)的重复包含.常见的条件编译指令如表 ...
- C语言-条件编译使用分析
1.基本概念 条件编译的行为类似于C语言中的if…else… 条件编译是预编译指示命令,用于控制是否编译某段代码 2.实例分析 条件编译初探 22-1.c #include <stdio ...
- C语言 条件编译(if )
#include <stdio.h> #define NUM -1 int main(int argc, const char * argv[]) { #if NUM > 0 pri ...
随机推荐
- Python+Selenium学习笔记19 - 自动发送邮件
发送简单的邮件 用一个QQ邮箱发送到另一个QQ邮件. 首先设置QQ邮箱,邮箱设置 -> 账号 开启SMTP服务,点击开启按钮,按提示进行操作,需要1毛钱的短信费.开启后如下所示 1 # codi ...
- Mapper注解与MapperScan注解
1.Mapper注解 在接口类上添加@Mapper,在运行时动态代理生成实现类 @Mapper public interface UserDao { // User getUser(); } 如果想要 ...
- 三维视觉惯性SLAM的有效Schmidt-EKF
三维视觉惯性SLAM的有效Schmidt-EKF An Efficient Schmidt-EKF for 3D Visual-Inertial SLAM 论文地址: http://openaccess ...
- Linux内存技术分析(上)
Linux内存技术分析(上) 一.Linux存储器 限于存储介质的存取速率和成本,现代计算机的存储结构呈现为金字塔型.越往塔顶,存取效率越高.但成本也越高,所以容量也就越小.得益于程序访问的局部性原理 ...
- GPU—加速数据科学工作流程
GPU-加速数据科学工作流程 GPU-ACCELERATE YOUR DATA SCIENCE WORKFLOWS 传统上,数据科学工作流程是缓慢而繁琐的,依赖于cpu来加载.过滤和操作数据,训练和部 ...
- 新的微芯片MCU增加了来自外部闪存的安全引导保护
新的微芯片MCU增加了来自外部闪存的安全引导保护 New Microchip MCU Adds Secure Boot Protection from External Flash 对于从外部SPI闪 ...
- jemeter压测, 高级应用: 发1万个请求,每个请求参数都不同, 使用CSV数据文件配置
今天接到一个压测任务, 数据源需要自己从测试环境库中取, 并且使用jemeter 请求, 每个请求参数都不相同 这里使用jemeter的 CSV数据文件来配置: 这样配置好后, 开始发送请求: csv ...
- springboot注解之@ConditionalOnProperty
最近在研究springboot的源码,看到很多@ConditionalOnXxx的注解,大概明白此注解的意思,就是判断条件,这个条件就是Xxx,例如ConditionalOnProperty就是判断配 ...
- 2021年Wordpress博客搭建
2021年WordPress博客搭建教程 这是一篇关于2021最新版的WP个人博客搭建教程.整篇文章会事无巨细的一步步讲述搭建博客的每一步. 0.前言 随着互联网和移动互联网的飞速发展,博客这一功能恍 ...
- UF_EVAL 曲线或边分析
Open C UF_EVAL_ask_arc 圆形曲线或边分析,得到曲线或边的信息UF_EVAL_ask_ellipse 椭圆曲线或边分析,得到曲线或边的信息UF_EVAL_ask_hyperbo ...