news 2026/6/9 20:55:17

跟我学C++中级篇——宏与constexpr

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
跟我学C++中级篇——宏与constexpr

一、综述

在C++语言中,宏与constexpr(const),主要于常量和表达式的处理,特别是在编译期计算时,有着重要的作用。很多开发者可能对二者的使用非常多,但二者到底有什么不同可能不是很清楚。或者说,无法清晰的描述出二者的不同,只可意会,无法言传。
下面将对二者在不同的角度进行细节上的区分和说明。

二、宏与constexpr的区别

对于宏于常量处理可以从形式和内容、编译期和作用域等角度进行对比,其区别在于:

  1. 类型检查
    对于宏来说,是不进行类型检查的,而constexpr作为C++中的关键字,是要进行强类型检查的
#definePI3.14159constexprintx=100;doubleret=PI*3;constexprdoubled=x*3;
  1. 作用域的处理
    宏只是单纯的替换,不受作用域的控制;而constexpr则不然,它作为关键字当然受作用的限制,如名空间等
#define PI 3.14 namespace Demo{ #define LEN 10 constexpr int d = 10; } int ret = PI*2; ret = LEN *2; ret = Demo::d *2;
  1. 应用范围
    宏可以用在预处理阶段(编译前)和条件编译,而constexpr只能用于编译阶段且不能用于条件编译,但它可用于编译期计算
#ifdefDEBUG#defineSIGNAL100#else#defineSIGNAL1#endif
  1. 对字符串的处理不同
    宏可以使用“#”和“##”来进行字符串的处理;而constexpr则只是一种关键字进行常量限定,但支持复杂的字符串操作
#defineSTRING(x)#x#defineCONCAT(s1,s2)s1##s2constevalautostr_concat(){returnstd::string_view("hello")+" "+"world";}
  1. 对调试的友好度
    宏由于只是在编译期进行替换动作,所以其对调试并不友好,调试相对困难;而constexpr则对调试非常友好,可以展现相关的错误信息,便于调试
  2. 异常的引入
    对宏来说,由于开发复杂,比如小括号的处理和换行符的处理往往导致异常的情况;而constexpr则定义清楚,安全可控
#defineMUL(x,y)x*y//表达复杂的情况下会出现问题MUL(2+3,10);//=32,期望是50
  1. 复杂编程
    宏可以从简单到复杂的应用,但使用宏来实现复杂的逻辑,对于开发者的水平要求非常高;而constexpr则只是一个关键字,谈不上简单复杂的应用一说。有兴趣的可以看一下前面的反射相关中的复杂的宏应用,此处不再赘述
  2. 可维护性
    简单的宏还好,但对于稍微复杂一些的宏来说,可维护性就相对差不少了;而对constexpr来说,可维护性只与其使用的场景有关而与其自身无关

需要赘述一下的是,在C++20以后,扩展了constexpr的应用范围,增加了consteval关键字,这都是对常量(表达式)的一种更广泛的推广应用。大家可紧密的跟踪新标准的中相关说明,不断的扩展自己的眼界。

三、应用场景选择

在前面的文中也反复提到过,在没有特殊的情况下,不建议使用宏,特别是复杂的宏开发。宏与C++的强类型语言本身还是有些相悖的,所以一般都是推荐使用constexpr。同时,constexpr对调试的友好性,也容易在出现问题后便于定位和解决问题。
但宏也有其优势之处,特别是在条件编译和预处理时,constexpr则只能望洋兴叹,力有所不逮。另外,对于控制头文件的重复包含、编译器或硬件平台的特性支持以及一些底层预定义应用的宏,也都是宏应用的优势之处。

四、例程

下面给出一个对比的例程:

#include<iostream>#include<chrono>#include<array>// 宏#defineSQUARE(x)((x)*(x))// constexprconstexprintconstSquare(intx){returnx*x;}constexprintcompileTest(){constintmRet=SQUARE(5);constexprintcRet=constSquare(5);static_assert(SQUARE(3)==7,"cacl err");//可修改7为9static_assert(constSquare(3)==9,"constexpr cacl err");return0;}intmain(){//编译期测试constexprintret=compileTest();intx=2;intmacRet=SQUARE(x);std::cout<<"cur cacl ret is:"<<ret<<","<<macRet<<std::endl;//编译期和运行期计算constexprintcSquare=constSquare(2);intrSquare=constSquare(x);std::cout<<"cur cacl ret is:"<<cSquare<<","<<rSquare<<std::endl;//加和计算inty=3;intsumRet=SQUARE(x+y);intcSumRet=constSquare(x+y);std::cout<<"cur cacl ret is:"<<sumRet<<","<<cSumRet<<std::endl;return0;}

五、总结

十八般武器各有各的优势,长得相近的武器未必就可以互相替代。哲学上不是有句名言么,“存在即合理”。宏和constexpr就是这种情形。在一个好的开发者的眼中,只有最合适的方法,没有最优的方法。至于如何选择宏和constexpr,多吃几回亏就好了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/6 5:21:29

华为够良心!时隔一年半,6款老荣耀喜提新版鸿蒙系统!

鸿蒙开发者工具 "华为良心依旧&#xff01;6款老荣耀机型喜提HarmonyOS4.2更新&#xff0c;包括V30、30系列等5G旗舰&#xff0c;时隔一年半仍获系统维护。升级前记得备份数据&#xff0c;但未来升级纯血鸿蒙希望不大。" 荣耀在2020年脱离华为独立后&#xff0c;无法…

作者头像 李华
网站建设 2026/6/9 16:09:55

集合初始化性能翻倍,C# 12集合表达式你真的用对了吗?

第一章&#xff1a;集合初始化性能翻倍&#xff0c;C# 12集合表达式你真的用对了吗&#xff1f;C# 12 引入的集合表达式&#xff08;Collection Expressions&#xff09;为开发者提供了更简洁、高效的集合初始化方式&#xff0c;尤其在频繁创建临时集合的场景下&#xff0c;性能…

作者头像 李华
网站建设 2026/6/9 17:23:14

如何预览HeyGem中的待处理视频?点击即可播放的交互设计

如何预览HeyGem中的待处理视频&#xff1f;点击即可播放的交互设计 在AI数字人内容爆发式增长的今天&#xff0c;企业越来越依赖自动化工具生成高质量虚拟形象视频。然而&#xff0c;一个常被忽视的问题是&#xff1a;用户上传了音频和视频后&#xff0c;真的能立刻确认这些素材…

作者头像 李华
网站建设 2026/6/9 17:26:59

推荐使用Chrome浏览器访问HeyGem WebUI界面确保最佳体验

推荐使用Chrome浏览器访问HeyGem WebUI界面确保最佳体验 在本地部署AI数字人视频生成系统时&#xff0c;你有没有遇到过这样的问题&#xff1a;上传文件卡住、进度条不动、预览黑屏&#xff0c;甚至点击“开始生成”后毫无反应&#xff1f;这些问题往往不在于模型本身&#xf…

作者头像 李华
网站建设 2026/6/9 17:24:15

Span<T>在实际项目中的应用(C#高性能数据处理实战案例)

第一章&#xff1a;Span 在实际项目中的应用&#xff08;C#高性能数据处理实战案例&#xff09; 在现代C#开发中&#xff0c; Span<T> 成为处理高性能数据场景的核心工具之一&#xff0c;尤其适用于避免内存分配、提升数据访问效率的场合。它提供了一种安全且高效的方式来…

作者头像 李华
网站建设 2026/6/6 21:40:09

仅限内部分享:企业级C#通信协议架构设计的7个关键决策点

第一章&#xff1a;企业级C#通信协议架构设计的核心挑战在构建企业级C#通信系统时&#xff0c;通信协议的架构设计面临多重技术挑战。这些挑战不仅涉及性能与安全性的平衡&#xff0c;还需兼顾可扩展性、跨平台兼容性以及系统间的互操作性。协议选择与性能优化 企业级系统通常需…

作者头像 李华