当前位置: 首页 > news >正文

【c++八股文】Day5:const和constexpr,define

非常棒的问题,这几个关键字(constconstexpr#define)都可以用来表示“常量”,但它们意义、作用时机和参与编译的方式完全不同,理解这些对掌握 C++ 编译模型和写出高质量代码非常重要。

我们从用途、语义、生命周期、编译阶段、类型检查、作用域、性能优化等维度系统性整理:


✅ 一、先看三者的简要对比

特性/关键词#defineconstconstexpr
类型安全❌(纯文本替换)✅(有类型)✅(有类型,且编译期常量)
编译阶段预处理阶段编译阶段编译阶段(要求常量表达式
编译器可见性❌(对编译器不可见)✅(符号存在)✅(符号存在且常量可折叠)
优化能力差(不利于调试优化)较好最佳
可以取地址✅(在符号表中)✅(但可能折叠为立即数)
支持复杂类型❌(只能是文本)
可用于数组长度✅(C++11起)
常量表达式限制不要求是编译期常量必须是编译期常量表达式

🧩 二、编译器行为层面解释

1. #define:预处理阶段文本替换

#define PI 3.14

🔍 行为:

  • 预处理阶段,编译器会把 所有出现 PI 的地方直接替换为 3.14
  • 编译器看不到 PI 这个标识符,调试器、类型系统也看不到
  • 不参与类型检查、作用域控制

📌 不推荐:

#define SQUARE(x) x * x
int y = SQUARE(1 + 2);  // → 展开为 1 + 2 * 1 + 2 → 错误

2. const:在编译阶段处理的只读变量

const double pi = 3.14;

🔍 行为:

  • pi 是一个具有类型和作用域的符号
  • 编译器会参与类型检查
  • 可以取地址(存在符号表中)
  • 如果优化器看到它不变,可能优化为立即数

📌 示例:

const int N = 10;
int arr[N];  // C++11 起允许

3. constexpr:编译阶段就能求值为常量的表达式

constexpr double pi = 3.14;
constexpr int square(int x) { return x * x; }

🔍 行为:

  • 要求变量或函数在编译期间就能确定值

  • 编译器会强制执行常量折叠(constant folding)

  • 可用于:

    • 数组大小
    • 模板参数
    • 枚举值
    • if constexpr 语句分支
  • 可定义常量表达式函数

📌 示例:

constexpr int N = square(3); // N = 9,在编译期完成计算
int arr[N];                  // 数组大小合法

⚠️ 三者在调试器中的差异

内容类型在调试器中是否可见是否能打断点是否能取地址
#define❌ 不可见(被替换掉)❌ 无法断点
const✅ 可见(有符号名)✅ 可以断点
constexpr⚠️ 可能折叠优化掉❌ 不一定能断点❌ 常常变成立即数

✅ 四、代码层级对比示例

#define LEN 100                     // 无类型,只是 100 的文本替换const int len1 = 100;              // 有类型,支持类型检查,可能折叠
constexpr int len2 = 100;          // 编译期常量,支持最强优化int arr1[LEN];   // ✅
int arr2[len1];  // ✅(C++11 起)
int arr3[len2];  // ✅(优先推荐)

🎓 五、适合用于什么场景?

使用场景推荐选项原因
简单常量替代constexpr类型安全 + 编译期求值 + 优化好
宏函数inline constexpr function避免宏展开错误,可调试
魔法数字、配置参数constexpr or const类型安全、可调试
条件编译(平台相关)#ifdef/#define预处理器语法只在这类场景合法
定义模板参数或数组大小constexpr编译期要求常量

✅ 六、语义分层总结图

       ┌────────────────────────────┐│       #define PI 3.14      │ ← 预处理,替换文本,无类型、无调试信息└────────────────────────────┘↓┌────────────────────────────┐│  const double pi = 3.14;   │ ← 有类型,有符号,有作用域,可调试└────────────────────────────┘↓┌────────────────────────────┐│ constexpr double pi = 3.14;│ ← 编译期常量表达式,最优性能和安全性└────────────────────────────┘

✅ 七、一句话总结

#define 是预处理器的文本替换,完全不参与类型系统;const 是只读变量,具有类型和作用域;constexpr 是编译期可求值的常量表达式,是现代 C++ 推荐的写法,支持最强类型安全与编译优化。

http://www.dtcms.com/a/270714.html

相关文章:

  • sql查询davinci看板数据
  • 【一起来学AI大模型】PyTorch DataLoader 实战指南
  • 极简相册管理ios app Tech Support
  • ARM汇编编程(AArch64架构)课程 - 第7章:SIMD与浮点运算
  • 2025杰理蓝牙芯片:各系列芯片特点及市场分析
  • 【手写 new 操作符实现 - 深入理解 JavaScript 对象创建机制】
  • 【Linux】权限的概念及理解
  • VR/AR在HMI中的创新应用:远程协作与维修的沉浸式体验
  • 类和对象拓展——日期类
  • 【实习篇】之Http头部字段之Disposition介绍
  • 使用 Docker 搭建 Rust Web 应用开发环境——AI教你学Docker
  • VR重现红军过雪山:一场穿越时空的精神洗礼​
  • MySQL 09 普通索引和唯一索引
  • MySQL 间隙锁
  • pytorch 自动微分
  • 半导体晶圆检测的基本知识
  • EGARCH
  • Linux C 目录流基本操作
  • Alloy VS Promtail:基于 Loki 的日志采集架构对比与选型指南
  • ECS由浅入深第四节:ECS 与 Unity 传统开发模式的结合?混合架构的艺术
  • Using Spring for Apache Pulsar:Publishing and Consuming Partitioned Topics
  • vue2 echarts中国地图、在地图上标注经纬度及标注点
  • AI应用实践:制作一个支持超长计算公式的计算器,计算内容只包含加减乘除算法,保存在一个HTML文件中
  • 「macOS 系统字体收集器 (C++17 实现)」
  • Oracle存储过程导出数据到Excel:全面实现方案详解
  • Java零基础笔记08(Java编程核心:面向对象编程高级 {继承、多态})
  • 【macOS】【Swift】【RTF】黑色文字在macOS深色外观下看不清的解决方法
  • yolo8实现目标检测
  • springMVC05-异常处理器
  • HashMap源码分析:put与get方法详解