条件编译 - 代码裁剪的工具 --进阶C语言

news/2024/11/17 1:36:01/文章来源:https://www.cnblogs.com/DSCL-ing/p/18414575

目录
  • 条件编译 - 代码裁剪的工具
    • 为何要有条件编译
    • 条件编译都在那些地方用?
    • 见一见条件编译的代码
    • 宏是否被定义 vs 宏是否为真or假
    • 编译器也能够自动帮你加上宏
      • GCC
      • VS2023-VS2019
    • #ifdef/#ifndef
    • #if
      • 注意事项
    • 让#if和#ifdef/#ifndef完全一样
    • 条件编译也支持嵌套
    • 一个使用#if defined能起到很好优化的用法

条件编译 - 代码裁剪的工具

为何要有条件编译

条件编译主要是用于代码裁剪,通过代码裁剪,能够快速实现某种目的,如版本维护(free版本,pro版本等,功能裁剪,跨平台性等.


条件编译都在那些地方用?

举个例子

我们经常听说过,某某版程序是完全版/精简版,某某版应用是商用版/校园版,某某软件是基础版/扩展版等。

其实这些软件在公司内部都是同一个项目,是多个源文件构成的。所以,所谓的不同版本,其实就是那些功能的有无;在技术层面上,公司为了好维护,可以维护多种版本;如果是使用条件编译,想使用哪个版本,就使用哪种条件进行裁剪就行。

如著名的Linux内核,功能上也是使用条件编译进行功能裁剪的,来满足不同平台的软件。

见一见条件编译的代码

int main()
{
#ifndef DEBUG   printf("hello debug\n");
#elif RELEASE   printf("hello release\n");
#else printf("hello unknow\n");
#endif   return 0;
}

宏是否被定义 vs 宏是否为真or假

#define DEBUG    // 宏被定义#define DEBUG 1  // 宏被定义,且值为真#define DEBUG 0  // 宏被定义,且值为假

宏为真假是在宏被定义之上的.


编译器也能够自动帮你加上宏

GCC
语法:gcc 源文件  -D 宏=值
#   gcc test.c -D MACRO=1 
VS2023-VS2019

image-20240508153946278

image-20240508154007078

在vs平台上用的不多.



#ifdef/#ifndef

#ifdef/#ifndef用于检测宏是否被定义,有没有值,是真是假不重要

#ifdef 检测宏是否已经定义,是则保留,否则裁剪;#ifndef则相反

用法举例:

image-20240507171846307

#ifdef/#ifndef一般只在头文件中使用


#if

#if的默认用法和#ifdef有一定区别,其他用法差不多,#if使用更频繁.

区别是#if如果定义了宏则要求必须要有值,没定义则当作假或者else.


注意事项

使用#if或#ifdef时,很容易会忘记写#endif.因为我们平常写if-else没有这个end,很容易会类比忘记掉#endif.所以在使用条件编译时,先把#if - #endif写上,后面就不再容易遗漏了.



让#if和#ifdef/#ifndef完全一样

#if模拟#ifdef:

#define MACRO
int main()
{
#if defined(MACRO)puts("MACRO defined!");
#elseputs("MACRO undefined!");
#endifreturn 0;
}

程序运行结果:

image-20240508160951829

如果是未定义呢? 没有别的名词,加个逻辑反就好啦

image-20240508170933763


条件编译也支持嵌套

#include<stdio.h>
#include<math.h>#define C    
#define CPP    int main()     
{             
#if defined(C)    #if defined(CPP)    puts("hello CPP");    #endif                  puts("hello C");    
#else                 puts("hello other");    
#endif                    return 0;    
}  

image-20240508173148156

注释掉#define C

image-20240508173245666

可以证明,条件编译是支持嵌套的.

不过,使用嵌套的代码阅读体验是比较差的,一般不建议使用嵌套,下面还有其他更好的代码写法推荐.



一个使用#if defined能起到很好优化的用法

[引用](C语言#if defined高级用法-CSDN博客)

在一个需要完成“多个宏定义来共同控制同一代码分支”的情况下,例如

  • TEST_1 或 TEST_2被定义,则选择执行1,2
#ifndef TEST_1
#define TEST_1
#endif#ifdef TEST_1puts("1");
#else#ifdef TEST_2puts("1");#elseputs("2");#endif
#endif
  • 或者, TEST_1和TEST_2均未定义,则选择执行1,否则执行2
#ifndef TEST_1puts("1");
#else#ifndef TEST_2puts("1");#elseputs("2");#endif
#endif

这样的代码看起来是比较冗余的,不好阅读,因为#ifdef是没有对应的"else if",我们只能采用这样的方式写.对比到一般使用的if-else,if()内可以是一个表达式,那#ifdef能否也能将宏定义组织成表达式呢?

看一下代码

#ifdef TEST_1 || TEST_2puts("1");
#elseputs("2");
#endif

这样的代码看起来是更简洁,更优雅.但它是错误的.

image-20240508163628082

因为ifdef和ifndef仅能跟一个宏定义参数,而不能使用表达式


虽然在vs下可以运行

image-20240508163859587

但是我们不推荐这样不能跨平台的代码.


因为#if需要判断真假而具有计算表达式的功能,

因此,使用#if defined#if !defined更好的选择.

  • TEST_1 或 TEST_2被定义,则选择执行1,否则执行2
#if defined TEST_1 || defined TEST_2puts("1");
#elseputs("2");
#endif
  • TEST_1 或 TEST_2未被定义,则选择执行1,否则执行2
#if !defined TEST_1 || !defined TEST_2puts("1");
#elseputs("2");
#endif


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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

这些年没来得及学习的一些 HTML5 标签

认识并学习下还没来得及学习的一些 HTML5 标签 <ruby> 标签 HTML <ruby> 元素被用来展示东亚文字注音或字符注释。 比如: <ruby>兄弟<rt>xiongdi</rt></ruby><rt> 元素包含字符的发音,字符在 ruby 注解中出现,它用于描述东亚字符的…

软件工程第二次作业

这个作业属于哪个课程 https://edu.cnblogs.com/campus/fzu/SE2024这个作业要求在哪里 https://edu.cnblogs.com/campus/fzu/SE2024/homework/13253这个作业的目标 变大变强学号 102201542项目名称:e了个mo github作业仓库链接:(https://github.com/zqh666nb/e-mo) !!!运行ma…

win11 nimi主机安装软路由

硬件 带两个LAN口的mini主机 软件 win11家庭版 openwrt一 安装hyper-v虚拟机 由于是win11家庭版,启用或关闭 Windows 功能里没有hyper-v win11家庭版启用Hyper-V的方法 创建脚本pushd "%~dp0" dir /b %SystemRoot%\servicing\Packages\*Hyper-V*.mum >hyper-v.…

帝国cms认证码怎么取消

取消帝国CMS中的认证码(也称为验证码),可以通过以下几种方法来实现: 1. 通过后台设置取消 如果你只是想在某些特定的操作中取消认证码,比如在会员注册、登录或后台管理时不需要验证码,可以尝试通过后台设置来取消:登录后台:登录帝国CMS的后台管理系统。进入系统设置:在…

dedecms修改文档标题最大长度

在DedeCMS中修改文档标题的最大长度可以通过以下几种方法实现: 方法一:通过后台设置登录后台:登录到DedeCMS的后台管理系统。进入系统设置:在后台管理界面,找到“系统”->“系统基本参数”。修改文档标题长度:在“系统基本参数”设置中,找到“其他选项”->“文档标…

织梦在导航栏下拉菜单中怎么调用当前栏目子类

在织梦CMS (DEDECMS) 中,要在导航栏的下拉菜单中调用当前栏目的子类,可以使用channelartlist标签来实现。下面是如何实现这一功能的具体步骤: 步骤 1: 使用channelartlist标签 在织梦CMS中,可以利用channelartlist标签来调用当前栏目的子类。下面是一个示例代码:<ul>…

帝国cms怎么上传图片

在帝国CMS中上传图片可以通过多种方式实现,具体取决于你是想在文章中插入图片还是批量上传图片到服务器。下面是两种常见的上传图片的方法: 1. 在文章编辑时上传图片 当你在撰写或编辑文章时,可以直接上传图片并插入到文章内容中:登录后台:登录帝国CMS的后台管理系统。进入…

c#委托事件订阅模型

namespace WinFormsApp2 {delegate void ShowName(object sender);//声明委托类型,委托类型可以理解为一类方法的类型 ,如此处的showbuttonname方法便是符合showName类型public partial class Form1 : Form{private event ShowName btnclick; //声明事件,此处相当于实例…

织梦cms调取栏目高亮特殊样式的限制字节方法

在织梦CMS中,如果你想要调取栏目并且为当前访问的栏目添加高亮显示效果,同时限制字节数,可以采用以下方法: 方法一:使用runphp 如果你熟悉PHP编程,可以通过在模板中使用runphp标签来实现这一功能。不过需要注意的是,runphp标签的使用可能会带来一定的安全隐患,因为它允…

dede怎么添加自定义属性

在DedeCMS中添加自定义属性可以通过修改数据库表来实现。以下是具体的步骤:登录数据库管理工具:登录到你的数据库管理工具,如phpMyAdmin。修改dede_archives表:寻找dede_archives表,并打开其结构。 找到flag字段,这是一个枚举类型字段,用于存储文档的一些标志。 编辑fla…

帝国cms标签模板在哪下载

帝国CMS的标签模板可以从多个途径下载:帝国CMS官方网站:访问帝国CMS的官方网站:在导航栏中找到“模板”选项,浏览并下载所需的模板。注意,标签模板通常是以 .et 为后缀的文件。第三方模板市场:一些第三方模板市场也提供帝国CMS的模板下载,例如 TemplateMonster、ThemeFo…

织梦dedecms后台反应特别慢和经常卡住怎么办?

织梦DedeCMS后台反应特别慢和经常卡住的问题可以通过以下几个方面来解决:屏蔽安全提示:根据资料,织梦后台的安全提示执行缓慢可能是导致卡顿的原因之一。你可以尝试屏蔽相关的代码。具体操作是在织梦后台管理目录下的 templets/index_body.htm 文件中,将第25行至第35行的部…