宏在C++中的替代解决方案

C/C++宏编程艺术:从基础技巧到现代替代方案 宏系统作为C/C++最古老的特性之一,既是强大的代码生成工具,也是滋生晦涩代码的温床。能用语言特性就不用宏:优先使用模板、constexpr等类型安全方案限制宏的作用域:用#undef及时取消宏定义为必要场景保留宏:条件编译、跨平台适配等场景不可替代严格代码审查:对宏代码实施更严格的评审标准。 阅读详情
 宏,在C语言中是个神的存在,能够玩出各种花样,也正因为此,才会给普通程序员造成不少的困扰。由于宏只在预编译阶段起作用,使得编译器无法检测其中的Bug,作为新时代的C++程序员,还是远离的好。

C++为宏提供了一些替代的解决方案,嗯,是一些。

  1. 常量定义
#define NUM 100

《EffectiveC++》的第一个条款,讨论的就是这个宏。由于宏是预编译程序来处理,所以NUM这个名字不会加入到符号表中,如果出现编译错误时,提示信息中就不会出现NUM,而是100,为排除错误增加了额外的障碍。

替代方案就是使用const来定义常量,或者使用枚举enum。

const int NUM = 100;

const常量放在头文件中,也不必担心存在多个实例的问题,对于const修饰的变量,编译器一般也会对其进行优化,不会出现多重定义的问题。

C语言中还有一个特殊的常量定义:NULL。其一般的定义为 #define NULL 0,指针的内容却是一个整型,这不符合常理。所以在C++11中使用nullptr代替了NULL。

2.函数定义

由于宏只是在代码中做字符串替代展开,所以,用宏定义的函数,实际上并没有减少代码的体积。另外,还有一些天然的缺陷,假设一个求平方的函数宏

[cpp] view plain copy
#definesquare(x)  (x*x)  
voidf(double d, int i)  
{  
square(d); //OK  
square(i++); //糟糕, (i++*i++)  
square(d+1); //更糟,(d+1*d+1)  
}  

纵然可以把参数加上括号来解决,#define square(x) ((x)*(x)),但i++被执行两次这个问题还是无法解决。

C++中的替代方案,就是使用inline函数。

[cpp] view plain copy
inline int square(intvalue)
{
return value*value;
}

inline函数具有函数的性质,参数传递不管是传值还是传引用,都不会对参数进行重复计算;同时会对参数做类型检查,保证代码的正确性;inline函数也是在代码中做代码展开,效率上并不比宏逊色。

如果整型不满足需求,还可以定义为模板:

[cpp] view plain copy
template
inline T square(T& value)
{
return value*value;
}

还有一种更离谱的函数定义形式:

[cpp] view plain copy
#defineNull_Check(p)\  
if(p == NULL) return;  

这种使用反斜杠定义的函数,更得注意,如果在反斜杠后多了个空格的话,有的编译器会出现变异错误,而提示信息嘛,你可能会困扰很久的。因为反斜杠会对空格这个字符做反义,就会在代码中的引入非法字符,人眼是很难发现这种错误的。

3.类型重定义

#defineDWORD unsigned int

这种类型重定义完全可以使用 typedef unsigned int DWORD 来替代。

4.条件编译

[cpp] view plain copy
#ifdefSystemA  
testA();  
#else//SystemB  
testB();  
#endif  

这种条件编译宏,一般在不同的产品或平台使用同一套代码的情况,大量出现。定义了SystemA的时候,SystemB的代码是不编译的,也就意味着你的代码没有时刻处于编译器的监控中。可以使用template技术来解决。

[cpp] view plain copy
constint SystemA = 1;
constint SystemB = 2;

template
void test()
{}
//定义不同的系统的特化版本
template<> void test(){ //SystemA的实现 }
template<> void test(){ //SystemB的实现 }

这样,不同的系统使用自己的模板即可,别人的代码也会同时接受编译器的检查,不至于出现遗漏编译错误的情况。

5.头文件包含

[cpp] view plain copy
#ifndeftest_h  
#definetest_h  
    //test.h的实现  
#endif  

为了防止头文件重复包含,C++中现在也只能这么做,目前没有别的替代方案。且看看原委,Bjarne Stroustrup在《C++语言的设计与演化》一书中,提供了一个include的设计,可惜的是并没有真正实现。(Cpp, 即C语言预处理器)

我曾经建议可以给C++本身增加一个include指示字,作为Cpp的#include的替代品。C++的这种include可以在下面三个方面与Cpp的#include不同:

1)如果一个文件被include两次,第二个include将被忽略。这解决了一个实际问题,而目前这个问题是通过#define和#ifdef,以非常低效而笨拙的方式处理的。

2)在include的正文之外定义的宏将不在include的正文内部展开。这就提供了一种能够隔离信息的机制,可以使这些信息不受宏的干扰。

3)在include的正文内容定义的宏在include正文之后的正文处理中不展开。这保证了include正文内部的宏不会包含它的编译单位强加上某种顺序依赖性,并一般地防止了由宏引起的奇怪情况。

对于采用预编译头文件的系统而言一般地说,对于那些要用独立部分组合软件的人们而言,这种机制都将是一个福音。请注意,无论如何这还只是一个思想而不是一个语言特征。

也就是说,这个想法在C++中并没有实现。

如果你没有很好的驾驭宏,那就敬而远之吧。

[C++中如何替换宏定义] C++中如何替换宏定义]在 C++ 中使用宏定义(#define)可以方便地定义常量、函数以及进行代码重用,但是也会存在一些问题,如难以调试、不安全等。为此,在实际开发中,我们应尽量采用 const、enum 和 inline 等语法来替代宏定义。 阅读详情

相关推荐

SAP BO系统启用邮件发送功能

目录 背景 维护邮件目标 启用邮件功能 背景 为了将BO报表或BO预警信息发送给特定的收件人,需要启用SAP BO系统的邮件发送功能。 维护邮件目标 1. 登录BO系统的中央管理控制台(CMC): http://<bo server name>:<port>/BOE/CMC 2. 点击“Organize”底下的“Servers”按钮进入BO服务器界面: 3. 点击“Servers List”进入服务器列表界面,右键点击JobServer&lt.

guowenming001的博客 1962

C++替代宏的功能实现的方法

在C++中,对于替代宏的功能实现,我们通常见到的有三种方法: 1.常量用const来替代实现 类似于#define A 10,是在程序的预编译期将所有的A用常量10替换掉,如果我们不想使用宏,就可以用const int A=10替换之前的用法,这一步将会在程序编译过程中将所有的A置为常量10,以此达到我们想要的目的。 2.有参宏函数用inline(内联函数)来替换实现 宏其实是在预编译时期进行了代...

pretysunshine的博客 3928

emqx Java 订阅以及发送 结合若依框架

emqx Java 订阅以及发送 结合若依框架

Spo的博客 1613

【C/C++】#define宏替换高级用法

传参数的宏替换 二、宏替换不会做表达的运算 三、宏替换多行—反斜杠连接 四、#undef取消宏替换 五、宏替换转字符串、拼接等用法 六、宏替换的优缺点宏替换的优点: 便于维护,提高代码的可读性 由于宏替换将代码片段在预处理期替换,可以提高程序的执行效率 宏替换的缺点: 没有安全类型的检查 宏定义在部分代码中可能不直观,可能不方便调试 宏替换不会运算求解

努力让自己的能力配得上梦想. 3841

从T型结到Wilkinson:5分钟搞懂功分器选型指南(附最新射频测试数据对比)

本文通过对比T型结、电阻型和Wilkinson三种功分器的核心原理与实测数据,提供了清晰的射频功分器选型指南。文章结合最新的2.4GHz ISM频段测试数据,分析了插入损耗、回波损耗和端口隔离度等关键指标,并针对窄带物联网、射频测试及合成系统等不同应用场景,给出了具体的选型建议和实战提醒,帮助工程师根据系统需求做出最优决策。

bush的博客 305

保姆级教程:手把手配置AutoSar诊断复位(Dcm 0x11服务联动BswM/EcuM)

本文提供AutoSar诊断复位(Dcm 0x11服务联动BswM/EcuM)的保姆级配置教程,详细讲解从诊断服务基础配置到BswM规则引擎搭建、服务端口映射及EcuM复位执行的完整流程。通过Vector配置工具的实际截图和代码片段,帮助开发者高效实现远程复位功能,并分享调试技巧与性能优化实践。

weixin_30756499的博客 543

C++中的宏替换

1.引子 #define cat(x, y) x ## y 那么cat(a, b)和cat(cat(a, b), c)的结果是啥. #define str_impl(x) #x #define str(x) str_impl(x) 的意图何在. 2.规则 宏替换是C/C++的预处理中的一部分,在C++标准中有4条规则来定义替换. 规则1:实参替换. 本条规则描述带参数的宏的替换过

baihacker的专栏 9041

CTF 命令执行绕过总结

tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示。或:rce-xor-or.php & rce-xor-or.py。# ls -t >shell 将输出输入到shell文件中。异或:rce-xor.php & rce-xor.py。%09(url传递)(cat%09flag.php)sh /flag 2>%261 //报错出文件内容。2、1使用空变量$*和$@,$x,${x}绕过。7、异或无符号(过滤0-9a-zA-Z)more:一页一页的显示档案内容。

jnszstmei的博客 1958

std::max,std::min错误:应输入标识符的解决方法

文章内容如题,主要提供 std::max,std::min错误:应输入标识符的解决方法

duiwangxiaomi的博客 2万+

MOS 管驱动设计细节,波形分析

一般认为MOSFET是电压驱动的,不需要驱动电流。然而,在MOS的G S两级之间有结电容存在,这个电容会让驱动MOS变的不那么简单。 如果不考虑纹波和EMI等要求的话,MOS管开关速度越快越好,因为开关时间越短,开关损耗越小,而在开关电源中开关损耗占总损耗的很大一部分,因此MOS管驱动电路的好坏直接决定了电源的效率。 对于一个MOS管,如果把GS之间的电压从0拉到管子的开启电压所用的时间越短,那么MOS管开启的速度就会越快。与此类似,如果把MOS管的GS电压从开启电压降到0V的时间越短,那么MOS管关断的

m0_50862404的博客 1万+

手把手教你学simulink(16.2)--基于Simulink的高通滤波器(High-Pass Filter)项目

基于Simulink的高通滤波器(High-Pass Filter)项目的详细实例介绍。这个项目将重点放在高通滤波器的设计、实现和仿真上,帮助你理解和应用高通滤波器在信号处理中的作用。

MHD0815的博客 926

浅析C++里面的宏 (转)

浅析C++里面的宏 (转)[@more@]说到宏,恐怕大家都能说出点东西来:一种预处理,没有分号(真的吗?)。然后呢?嗯.......茫然中......好吧,我们就从这开始说起。最常见的宏恐怕是#include了,其次就是#de...

cuiji1279的博客 128

1、机器学习在环境科学中的应用与经典数据分析基础

本文介绍了机器学习在环境科学中的广泛应用,包括卫星遥感、气候预测、空气质量预报等领域,并系统回顾了经典数据分析的基本概念,如期望、方差、协方差和相关性及其显著性检验。同时,文章阐述了贝叶斯定理、判别函数与分类、聚类分析等方法的原理与应用,强调了经典统计方法与机器学习技术的互补关系。最后展望了未来环境科学中数据分析的发展方向,强调多学科融合与方法创新的重要性。

stone的博客 143

vc中对标准库std::min,max,swap的支持问题

最近在看c++标准库的资料,对比VC测试后发现,VC并不完全支持标准库的定义对std::min,max vc采用了另外的实现:_cpp_min,_cpp_max,例子代码:cout (1,2)  cout (1.0,2.0)  而swap的实现估计要自己做了。 另外可以参考文档:http://www.vckbase.com/bbs/prime/viewprime.a

我爱翰宝宝 7133

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

关于NOMINMAX这个预处理宏

标准库在<algorithm>头中定义了两个模板函数std::min() 和 std::max()。通常用它可以计算某个值对的最小值和最大值。可惜在 Visual C++ 无法使用它们,因为没有定义这些函数模板。原因是名字min和max与<windows.h>中传统的min/max宏定义有冲突。为了解决这个问题,Visual C++ 定义了另外两个功能相同的模板:...

weixin_30505043的博客 856

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

告别 # 与 ##:预处理器元编程的现代 C++ 替代方案

本文探讨如何用现代C++特性替代传统的预处理器宏(##和#)。文章指出,宏虽然功能强大但存在类型不安全、调试困难等问题。对于标记粘贴(##),建议使用模板和if constexpr实现类型安全的代码生成;对于字符串化(#),推荐采用C++20的source_location和第三方反射库来改善调试体验。现代C++特性能够提供更安全、更易维护的解决方案,使代码摆脱对预处理器宏的依赖。文章强调,在绝大多数场景下,模板元编程和编译期特性都是比宏更优的选择。

greenspan的专栏 1290

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

【C++】学习笔记——C++入门_3

由于形参只是实参的一份临时拷贝,改变形参并不能改变实参的值,所以我们一般通过传实参的地址,通过指针的方法来改变实参。在返回类型中加上引用后,我们返回的是a的别名 ,但是a已经销毁了,所以a空间内的内容以及不确定了,返回的a的别名导致非法访问,结果未知。当然,引用可以套用,我可以给a取别名为b,也可以给b取别名为c,此时a,b,c三者为同一变量。在一般的函数中,我们都是类似上面的代码那样返回的。,这样,新称号就是原名字的别名,两个名称都表示同一个变量。,编译器不会为引用变量开辟内存空间,它和它引用的变量。

m0_69828905的博客 680

【std max,std min错误 解决方法】

使用VS2010编写的C++程序 std:min 转换到 VS2013无法识别,显示“错误:应输入标识符”。 标准库在头中定义了两个模板函数std::min() 和 std::max()。通常用它可以计算某个值对应的最小值和最大值。可惜在 Visual C++ 无法使用它们,因为没有定义这些函数模板。原因是名字min和max与中传统的min/max宏定义有冲突。 解决方法: 1、为了解决这个问题,Visual C++ 定义了另外两个功能相同的模板:_cpp_m...

qq_42222110的博客 1737

C/C++中do...while(0)的妙用

【本文转载了2篇blog关于do...while(0)的巧妙用法,这两篇文章内容水平很高,在此谢谢原文作者,如需转载请保留原文作者的连接(而不是我的连接)。原文如下: http://www.devbean.net/2014/01/do-while-in-macro/ http://www.cppblog.com/SmartPtr/archive/2007/07/03/27443.html 】

code_robot的专栏 878

C++内联函数与宏定义的性能与调试对比

在C/C++开发中,代码优化是提升性能的关键手段。内联函数和宏定义作为两种常见的优化方式,其核心差异在于编译处理机制。内联函数通过编译器智能展开,保持类型安全性和调试支持,适用于需要稳定性和可维护性的场景;而宏定义则是预处理器执行的文本替换,虽然灵活但缺乏类型检查。从技术价值看,内联函数更适合现代C++开发,特别是在模板元编程和constexpr应用中表现优异。实际工程中,游戏引擎如Unity的调试和性能优化往往需要权衡两者。合理选择内联函数和宏定义,能有效平衡代码效率和可维护性。

385

宏和内联函数

#define 定义宏 例1:宏常量 #define MAX 10 int main() { const int a = 10; int b = 20; int* pa = (int*)&a; *pa = 100; printf("%d\n", MAX); printf("%d\n", a); printf("%d\n", b); cout << a << endl; cout << *pa << endl; return

徐佳佳的博客 300

C++ 中的宏用法

我仍然看到很多地方#defines(在 C 和 C++ 中都有),而且我几乎可以肯定在大多数地方,这些并不是真正需要的。有时,我还了解到有一种方法可以用模板或其他构造来表达/替换宏,所以我最终决定列出我遇到的用例,其中用其他东西替换宏是有意义的,以及我不知道有任何替代方案。

Jet_58的博客 1611

【为什么】C++中的宏

C++宏的简单理解 C++中的宏是一种代码片段,可以被宏的值所替换。宏是用#define指令来定义的,用#undef指令来取消定义。宏有两种类型:类对象宏和类函数宏。 类对象宏就像一个常量,只不过不需要分配内存空间。 类函数宏就像一个函数,只不过不需要调用和返回。 大白话来说,宏就是一种让你写代码时更方便、更简洁、更灵活的工具 举例说明 假设你想定义一个宏,用来计算两个数的最大值。你可以这样写:...

C++十万个为什么 1593

一文讲清楚c/c++中的宏

使用。

qq_39350172的博客 2743
上一篇: 网络TCP建立连接为什么需要三次握手而结束要四次
下一篇: 数据段、代码段、堆栈段、BSS段的区别
lm_123_456
博客等级 码龄11年 35粉丝 86原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值