2026/2/5 21:28:54
网站建设
项目流程
基本网站建设,wordpress 菜价插件,WordPress软件连接不了网站,wordpress主题微信验证码《你真的了解C吗》No.015#xff1a;constexpr 的进击——编译期计算的极限
导言#xff1a;偷走运行时间的人
在传统的 C 认知中#xff0c;程序被分为明显的两个阶段#xff1a;编译期#xff08;处理类型、分配布局#xff09;和运行期#xff08;执行逻辑、计算数值…《你真的了解C吗》No.015constexpr 的进击——编译期计算的极限导言偷走运行时间的人在传统的 C 认知中程序被分为明显的两个阶段编译期处理类型、分配布局和运行期执行逻辑、计算数值。但constexpr的出现彻底模糊了这两者的界限。如果你认为constexpr只是const的增强版那么你可能错过了现代 C 最强大的性能优化手段。constexpr的本质是将原本属于运行时的计算压力提前到编译阶段由编译器承担实现真正的“运行时零成本”。一、constvsconstexpr身份的本质区别很多人分不清这两者其实它们的侧重点完全不同const只读变量它保证的是变量在初始化后不能被修改。但它并不要求初始化的值必须在编译期确定。intx;std::cinx;constintyx;// 合法但 y 的值直到运行时才知道constexpr常量表达式它要求值必须在编译期就能算出来。如果编译器算不出来直接报错。constexprintz105;// 编译器直接把 z 替换成了 15二、 编译期函数双重身份的“变形金刚”constexpr修饰函数时赋予了它一种极其聪明的特性按需计算。1. 定义一个编译期函数constexprlonglongfactorial(intn){returnn1?1:n*factorial(n-1);}2. 它是如何根据参数“变形”的场景 A常量参数当你传入一个字面量如10并将其赋值给constexpr变量时计算发生在编译期。最终的机器码里没有任何递归调用只有一个预算好的结果。constexprautoresfactorial(10);// 编译期完成运行时速度无穷快场景 B动态参数如果你传入的是用户输入或运行时变量constexpr函数会自动退化为普通函数。intn;std::cinn;longlongresfactorial(n);// 自动切换为普通的运行时递归这就是 C 的精妙之处你只需要编写一套逻辑编译器会尽可能在编译期帮你压榨性能实在不行再交给运行时。三、if constexpr编译期的分支剪枝 (C17)在处理模板时我们经常遇到这种困境某个分支的代码在某种类型下是编译不过的。if constexpr解决了这个问题它会让不符合的分支直接在代码中“物理消失”。templatetypenameTvoidprocess(T t){ifconstexpr(std::is_pointer_vT){std::cout*tstd::endl;// 非指针类型编译时这段代码会被丢弃避免报错}else{std::couttstd::endl;}}四、 为什么要追求“编译期计算”极致性能原本需要运行时计算的结果现在耗时为 0。安全性如果逻辑有误如除以零编译器会在编译时直接报错而不会等到用户手里才崩溃。ROM 友好对于嵌入式开发constexpr数据可以直接存储在只读的 Flash 中而不占用宝贵的 RAM。五、 总结最好的优化就是不运行constexpr是 C 走向“元编程”平民化的里程碑。它告诉我们如果一个值能预先算出就用constexpr把它算出来。如果一个函数既能静态算又能动态跑就把它声明为constexpr。下一篇预告既然我们已经深入到了编译期和运行期的边界那么是时候聊聊 C 中最容易引起“内存战争”的话题了。为什么现代 C 强烈建议你忘掉new和delete➡️《你真的了解C吗》No.016智能指针的幻觉 (The Illusion of Smart Pointers): unique_ptr 与 shared_ptr 的设计哲学。