C语言#if、##ifdef、#ifndef的用法详解

news2024/9/20 1:11:07

假如现在要开发一个C语言程序,让它输出红色的文字,并且要求跨平台,在 Windows 和 Linux 下都能运行,怎么办呢?

这个程序的难点在于,不同平台下控制文字颜色的代码不一样,我们必须要能够识别出不同的平台。

Windows 有专有的宏_WIN32,Linux 有专有的宏__linux__,以现有的知识,我们很容易就想到了 if else,请看下面的代码:

#include<stdio.h>
intmain(){
if(_WIN32){
system("color 0c");
printf("http://csdn.net\n");
}elseif(__linux__){
printf("\033[22;31mhttp://csdn.net\n\033[22;30m");
}else{
printf("http://csdn.net\n");
}

return0;
}

但这段代码是错误的,在 Windows 下提示 __linux__ 是未定义的标识符,在 Linux 下提示 _Win32 是未定义的标识符。对上面的代码进行改进:

#include<stdio.h>
intmain(){
    #if _WIN32
system("color 0c");
printf("http://csdn.net\n");
    #elif __linux__
printf("\033[22;31mhttp://csdn.net\n\033[22;30m");
    #else
printf("http://csdn.net\n");
    #endif

return0;
}

#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>
intmain(){
    #if _WIN32
printf("This is Windows!\n");
    #else
printf("Unknown platform!\n");
    #endif

    #if __linux__
printf("This is Linux!\n");
    #endif

return0;
}

#ifdef 的用法

#ifdef 用法的一般格式为:

#ifdef 宏名
程序段1
#else
程序段2
#endif

它的意思是,如果当前的宏已被定义过,则对“程序段1”进行编译,否则对“程序段2”进行编译。

也可以省略 #else:

#ifdef 宏名
程序段
#endif

VS/VC 有两种编译模式,Debug 和 Release。在学习过程中,我们通常使用 Debug 模式,这样便于程序的调试;而最终发布的程序,要使用 Release 模式,这样编译器会进行很多优化,提高程序运行效率,删除冗余信息。

为了能够清楚地看到当前程序的编译模式,我们不妨在程序中增加提示,请看下面的代码:

#include<stdio.h>
#include<stdlib.h>
intmain(){
    #ifdef _DEBUG
printf("正在使用 Debug 模式编译程序...\n");
    #else
printf("正在使用 Release 模式编译程序...\n");
    #endif

system("pause");
return0;
}

当以 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
intmain(){
    #if NUM ==10|| NUM ==20
printf("NUM: %d\n", NUM);
    #else
printf("NUM Error\n");
    #endif
return0;
}

运行结果:

NUM: 10

再如,两个宏都存在时编译代码A,否则编译代码B:

#include<stdio.h>
#define NUM1 10
#define NUM2 20
intmain(){
    #if(defined NUM1 &&defined NUM2)
//代码A
printf("NUM1: %d, NUM2: %d\n", NUM1, NUM2);
    #else
//代码B
printf("Error\n");
    #endif
return0;
}

运行结果:

NUM1: 10, NUM2: 20

#ifdef 可以认为是 #if defined 的缩写。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/190285.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023最新版easyrecovery数据恢复软件免费版测评

大家好&#xff0c;关于easyrecovery数据恢复软件免费版很多朋友都还不太明白&#xff0c;今天小编就来为大家分享关于easyrecovery数据恢复软件免费版下载使用的知识&#xff0c;希望对各位有所帮助&#xff01; EasyRecovery其实是目前为止我用的最喜欢的一款数据恢复软件&a…

C++string的模拟实现(上篇)

目录 一.命名空间的封装与交换函数模板 1.命名空间的封装与类的定义 2.交换函数模板 二.string类的四个重要默认成员函数 1.构造函数的类外定义&#xff1a; 2.析构函数在类外的定义 3.拷贝构造函数在类外的定义 4.赋值运算符重载在类外的定义 5.关于两个string对象…

在线 OJ 项目(一) · 项目介绍 · 进程与线程 · 实现编译运行模块

一、项目介绍二、导入依赖、创建基本项目结构导入依赖创建基本项目结构三、进程、线程的基础知识回顾四、封装操作进程的工具类五、实现 “编译运行” 模块 Task 类六、封装读写文件的方法修改 JDK 版本七、Task 类的实现八、整理一下项目列表一、项目介绍 项目实现一个在线 O…

煤矿AI智能视频分析识别系统 opencv

煤矿AI智能视频分析识别系统通过opencvpython 深度学习网络模型&#xff0c;对皮带跑偏、撕裂、堆煤、异物、非法运人、有煤无煤状态等异常情况&#xff0c;以及人员工服穿戴、反光衣、安全帽、睡岗离岗、打电话、抽烟等行为进行自动抓拍存档。OpenCV基于C实现&#xff0c;同时…

【正点原子FPGA连载】第二十八章Linux并发与竞争 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

1&#xff09;实验平台&#xff1a;正点原子MPSoC开发板 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id692450874670 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html 第二十八章Linux…

【splishsplash】Houdini粒子的导入与导出

Houdini粒子的导入与导出 Houdini导入到splish 在Houdini中使用file导入任意几何模型 使用points from volume采样点&#xff0c;使其粒子化 使用file导出粒子化之后的模型&#xff0c;后缀写bhclassic 创建json场景文件&#xff08;建议放到MyScences文件夹&#xff09; …

C语言指针是什么?

计算机中所有的数据都必须放在内存中&#xff0c;不同类型的数据占用的字节数不一样&#xff0c;例如 int 占用 4 个字节&#xff0c;char 占用 1 个字节。为了正确地访问这些数据&#xff0c;必须为每个字节都编上号码&#xff0c;就像门牌号、身份证号一样&#xff0c;每个字…

HTTP协议 | 青训营笔记

1、概述 HTTP协议&#xff0c;超文本传输协议 应用层的协议&#xff0c;基于TCP协议&#xff0c;简单可扩展&#xff08;可以自定义header&#xff09; 每个HTTP请求都可以分为请求和响应两个部分 无状态的&#xff08;不知道之前的请求是携带过什么信息&#xff09; 2、协…

【Qt】8.QPainter、高级设置、手动调用绘图事件、绘图设备、文件操作、文件信息

目录 QPainter 代码 widget.h widget.cpp 结果 高级设置 代码 widget.h widget.cpp 结果 手动调用绘图事件 代码 widget.h widget.cpp 结果 绘图设备 代码 widget.h widget.cpp 结果 文件操作 代码 widget.cpp 结果 文件信息 代码 widget.cpp 结果…

一文带你看懂健康管理系统----IPMI

目录 1. IPMI概述 2. IPMI系统设计 3. 主BMC模块设计 5. 从IPMI模块设计 6. 名词解释 6. 代码 1. IPMI概述 智能平台管理接口&#xff08;IPMI&#xff1a;Intelligent Platform Management Interface&#xff09;是一项应用于服务器管理系统设计的标准&#xff0c;由Int…

BSN-DDC基础网络详解(一):基础介绍

BSN-DDC基础网络推出已经一年了&#xff0c;得到了行业应用方和广大开发者的高度认可。一年中BSN产品技术团队也在根据市场业务需求不断更新功能服务&#xff0c;我们将通过本系列文章为大家系统化介绍DDC网络的功能和使用&#xff0c;为感兴趣的朋友提供学习帮助。BSN-DDC基础…

历史与今日的事件

作者简介&#xff1a;一名在校云计算网络运维学生、每天分享网络运维的学习经验、和学习笔记。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 前言 1.2023年1月31日中国最新量子计算机“悟空”即将问世&#xff0c…

【34】C语言 | 动态内存管理

目录 1.为什么存在动态内存分配 2、动态内存函数的介绍 2.1 malloc和free 2.2 calloc 2.3 realloc 1.为什么存在动态内存分配 我们已经掌握的内存开辟方式有: int val 20; //在栈空间上开辟四个字节 char arr[n] {0}; //在栈空间上开辟10个节的连续空间 但是上述的开辟…

mPEG-SS-NHS甲氧基聚乙二醇-二硫键-琥珀酰亚胺酯

mPEG-SS-NHS甲氧基聚乙二醇-双硫键-活性酯 名称&#xff1a;甲氧基聚乙二醇-双硫键-琥珀酰亚胺酯 英文名称&#xff1a;mPEG-SS-NHS 存储条件&#xff1a;-20C&#xff0c;避光&#xff0c;避湿 用 途&#xff1a;仅供科研实验使用&#xff0c;不用于诊治 外观: 固体或粘性…

【c语言进阶】动态通讯录

&#x1f680;write in front&#x1f680; &#x1f4dc;所属专栏&#xff1a; c语言学习 &#x1f6f0;️博客主页&#xff1a;睿睿的博客主页 &#x1f6f0;️代码仓库&#xff1a;&#x1f389;VS2022_C语言仓库 &#x1f3a1;您的点赞、关注、收藏、评论&#xff0c;是对我…

彭博:预订量未及预期,索尼大幅削减PS VR2首季订单

在索尼VR新品&#xff1a;PS VR2正式发货前夕&#xff0c;彭博社爆料称&#xff1a;因预订量不及预期&#xff0c;索尼已经大幅削减PS VR2首季订单量。消息人士称&#xff0c;索尼PS VR2发布后首个季度的订单目标是200万台&#xff0c;现已根据预订量减半&#xff0c;至约100万…

iOS 视频播放器开发

需求设计 做一个小学生教育辅导视频播放器。 参考小猿搜题视频播放器 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L0GsyFSt-1675164972791)(https://tva1.sinaimg.cn/large/008vxvgGgy1h9xk4fm5xfj31sx0u0mz0.jpg)] [外链图片转存失败,源站可…

Java中的JCA对基于密码的加密进行成功的蛮力搜索攻击所需的时间估计

对于JCA中基于密码的DES加密实现&#xff0c;固定一些盐和迭代计数&#xff0c;并记录加密/解密所需的平均时间;估计成功进行蛮力搜索攻击所需的时间Name: NIHAO DONG Number: 201476606 Password List:N Password 1 P$$W0rD 2 thisismypassword 3 VeryLongP$$W0rD fi…

[0CTF 2016]piapiapia(字符逃逸详解)

目录 知识点 信息收集 尝试SQL注入 源码目录扫描 代码审计 payload生成 知识点 信息泄露参数传递数组绕过字符串检测反序列化字符逃逸 信息收集 收集到了一只超可爱的小喵 尝试SQL注入 用户名不存在的回显 密码无效的回显 用户存在&#xff0c;密码错误的回显 判断闭…

STC15系列PWM功能相关功能寄存器介绍

STC15系列PWM功能相关功能寄存器介绍✨以下数据来源于stc15手册。 &#x1f4d3;增强型PWM波形发生器相关功能寄存器总表 1. 端口配置寄存器&#xff1a;P_SW2 2.PWM配青寄存器:PWMICFG CBTADC: PWM计数器归零时 (CBIF1时) 触发ADC转换 – 0:PWM计数器归零时不触发ADC转换 – …