尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
[C++ 基础核心] 为什么 constexpr 指针编译报错?打破 declarations 结构与右左法则的语法高墙 | CppCon 精华
导读摘要在 C 开发中我们经常遇到难以读懂的复杂声明或令人困惑的编译报错。比如为什么constexpr int *p;会直接报错而const int *p;却能顺利通过本博文基于 CppCon 2022 Ben Saks 的演讲“Back to Basics: Declarations in C”用**“修饰性零件”与“地基”**等生动比喻从零剖析 C 声明的底层解构式。文章详细拆解了decl-specifier-seq与declarator-list的爱恨情仇详解了读懂复杂声明的“右左法则”并以专家视角深度扩展了typename模板消除歧义、万能引用与引用折叠等现代 C 前沿机制。核心收获彻底搞懂 C 声明的底层编译逻辑免受编译报错折磨 前言那个让人百思不得其解的报错在写 C 代码时你是否写过类似这样的代码constint*p1;// 正常编译无任何警告constexprint*p2;// 编译报错error: default initialization of an object of const type const int * (or similar)这时候你的脑海中一定有很多小问号const和constexpr不都代表常量吗为什么一个不需要初始值而另一个必须初始化它们修饰的到底是指针本身还是指针指向的数据今天我们就跟着 C 标准委员会专家 Ben Saks一起拆解 C 声明Declarations的底层原理打碎这堵语法高墙️ 第一章声明 vs 定义——变量的“户口登记”与“分房入住”在进入复杂语法前我们先理清两个最容易混淆的词声明Declaration与定义Definition。[!TIP]生活类比声明就像是给孩子上户口登记名字。你跟派出所说“我们家要多一个叫张三的人了。” 此时派出所知道了这个名字但并没给张三分配具体的住房。定义则是真正盖楼并分房入住。不仅登记了名字还分配了实在的物理内存空间。// 仅声明 externintx;// 登记“有一个整型变量 x 在别处我们先用它”voidfoo(inta);// 登记“有一个函数 foo 接收 int具体实现待会儿说”structWidget;// 登记“有一个叫 Widget 的结构体类型”// 同时也定义 intx;// 盖楼在内存里划出 4 字节给 xvoidfoo(inta){}// 盖楼为 foo 分配函数体代码区structWidget{intid;};// 盖楼明确了 Widget 里面长啥样[!IMPORTANT]C 黄金法则在 C 中所有定义都是声明但并不是所有声明都是定义。编译器在编译期只需要知道名称的“声明”就可以编译但连接器在最后打包时必须找到“定义”否则就会报unresolved external symbol错误。 第二章解构 C 声明的底层结构C 的声明语法源自 C 语言。Ben Saks 指出几乎所有 C 声明都可以被拆解为两个核心组件decl-specifier-seq declarator-list ; \text{decl-specifier-seq} \quad \text{declarator-list};decl-specifier-seqdeclarator-list;换句话说声明就是【地基基类型说明符】【各种修饰性零件声明符】。int const *p1, *const p2; └────────┘ ──┬── ───┬── │ │ │ decl-specifier-seq │ │ (地基) │ declarator 2 (零件) │ declarator 1 (零件)2.1 地基decl-specifier-seq声明说明符序列这部分定义了变量的基础类型以及存储属性。它们会作用于后面逗号分隔的所有变量。基本类型int、double、Widget等CV 限定符const、volatile存储属性static、extern、thread_local常量级别修饰constexpr、consteval2.2 零件declarator-list声明符列表这部分用来决定我们声明的到底是一个普通的变量还是它的指针、引用或数组。修饰符*指针、左值引用、右值引用、[]数组、()函数标识符变量的名称。[!CAUTION]最经典的新手陷阱int*p,q;很多人以为p和q都是指针。但实际上int是地基应用于全部。*p是第一个零件声明p是指针。q是第二个零件由于没有*修饰它只是普通的int变量。正确的读法是p是int*而q是int。 第三章East Const 哲学与“右左法则”3.1 为什么推荐 “East Const”因为decl-specifier-seq里的说明符可以任意排列所以下面两行是等价的constintx10;// West Const (左派)intconstx10;// East Const (右派)Ben Saks 强烈推荐使用East Const将const写在类型的右边。因为这能极大地帮助我们使用从右向左Right-to-Left的规则来读懂声明。3.2 终极阅读密码右左法则 (Right-to-Left Rule)想读懂任何复杂的 C 声明只需要像剥洋葱一样从标识符开始先向右看再向左看。实战演练 1int const *p;找到标识符p。往右看什么都没有。往左看遇到*⟹p是一个指针pointer to…。继续往左看遇到const⟹ 指向一个常量const…。继续往左看遇到int⟹ 常量是int。翻译p是一个指向常量整型的指针。指针可变内容不可变。实战演练 2int *const p;找到标识符p。往右看什么都没有。往左看遇到const⟹p本身是常量const…。继续往左看遇到*⟹ 这个常量是一个指针pointer…。继续往左看遇到int⟹ 指向int。翻译p是一个指向整型的常量指针。指针不可变但内容可变。int const * p ; vs int * const p ; (4) (3) (2) (1) (4) (3) (2) (1) └───────┬─────┘ │ │ └─────┬─────┘ │ │ │ │ const int 指针 int const指针 第四章解密为什么constexpr int *p;报错回到前言的痛点问题为什么const int *p;能过而constexpr int *p;报错通过第三章的拆解我们来看看编译器是怎么理解这两个声明的const int *p1;const是类型限定符它修饰的是基类型int。p1是一个普通的指针它指向const int。既然p1只是普通变量它在声明时不需要赋初值。constexpr int *p2;重点来了constexpr不是常规的类型限定符它是非类型说明符它修饰的是整个被声明的变量本身。因此无论你把constexpr写在左边还是右边它都等价于将指针本身声明为常量即int *const p2;。在 C 中所有常量对象在声明时都必须初始化如果不给初始值编译器就不知道它的常量值是什么自然会无情报错。// 修复方法staticintval42;constexprint*p3val;// ✅ 成功编译p3 本身在编译期是固定地址的常量指针 第五章专家深潜——超越视频的延伸硬核知识以下内容是站在 C 专家视角为你补充的高阶声明技巧与底层机制。5.1 消除编译歧义的typename在模板泛型编程中编译器经常会遇到“傻傻分不清”的尴尬templatetypenameTvoidrun(){T::NestedType*p;// ⚠️ 编译器抓狂了}编译器的两难处境如果T::NestedType是一个类型那这一行是声明p是一个指向该类型的指针。如果T::NestedType是一个静态变量那这一行是乘法表达式T::NestedType乘以p。C 标准规定默认情况下依赖于模板参数的嵌套名字Dependent Names一律被视为非类型即变量/值。所以为了让声明成立我们必须加上typenametemplatetypenameTvoidrun(){typenameT::NestedType*p;// ✅ 明确告诉编译器这真的是个类型声明}5.2 万能引用Forwarding References与引用折叠在声明中通常代表右值引用但如果配合类型推导它就变成了“万能引用”templatetypenameTvoidprocess(Targ);// T 是万能引用既能接左值也能接右值当左值传入时T会被推导为左值引用如int此时声明中就会出现“引用的引用”int arg。C 通过**引用折叠Reference Collapsing**来强行平展这种多重引用 (左值引用) (左值引用) (左值引用) (右值引用)[!TIP]极简口诀见左即左——只要有一个左值引用参与折叠结果必定折叠为单。只有当全部为双时结果才是双。 第六章一图胜千言——C 声明全景思维导图C 声明结构decl-specifier-seq(地基 / 属性与基类型)declarator-list(零件 / 修饰符与名称)基本类型 (int, double)CV限定符 (const, volatile)非类型说明符 (constexpr, static)* (指针) / (引用)[ ] (数组)( ) (函数)constexpr 修饰变量本身constexpr 指针等价于 *const 指针常量必须当场初始化万能引用 (T / auto)引用折叠规则 总结三步读懂任何 C 声明寻找标识符从变量名开始出发。右看再左看先看右边有没有数组[]或函数()再看左边有没有指针*或引用。分清地基与零件基类型如int const是所有人共有的而*或仅仅属于绑在它身边的那个变量。记住用 East Const 的视角看世界复杂声明也不过是各种积木零件的组合 推荐阅读 系列文章本文是CppCon “Back to Basics” 系列精讲的第 6 篇SEO 长尾关键词布局C 声明与定义区别、constexpr 指针编译报错、C 右左法则读复杂声明、decl-specifier-seq 与 declarator 区别、East Const 优缺点、typename Dependent Names 消除歧义、万能引用与引用折叠原理视频来源CppCon 2022 - Back to Basics: Declarations in C - Ben Saks本文作者立场以 C 标准专家视角结合视频内容与实际开发经验撰写。如有疑问欢迎评论区讨论
RELATED

相关推荐

定时/计数器:从原理到实战,解锁单片机精准时序控制

定时/计数器:从原理到实战,解锁单片机精准时序控制

1. 定时/计数器:单片机的时间指挥官第一次接触51单片机时,你可能用过delay()函数做延时——让CPU空转循环来消耗时间。这种简单粗暴的方式就像让厨师亲自数秒煮鸡蛋,不仅效率低下,还会耽误其他工作。而定时/计数器就是为解决这个问…

📅 2026/9/12 7:19:20
远程桌面游戏手柄控制神器:RdpGamepad完全指南

远程桌面游戏手柄控制神器:RdpGamepad完全指南

远程桌面游戏手柄控制神器:RdpGamepad完全指南 【免费下载链接】RdpGamepad Remote Desktop Plugin for Xbox Gamepads 项目地址: https://gitcode.com/gh_mirrors/rd/RdpGamepad 还在为远程桌面连接时无法使用Xbox游戏手柄而烦恼吗?RdpGamepad正…

📅 2026/8/22 17:40:56
Snap Hutao:Windows平台上的专业原神工具箱完全指南

Snap Hutao:Windows平台上的专业原神工具箱完全指南

Snap Hutao:Windows平台上的专业原神工具箱完全指南 【免费下载链接】Snap.Hutao 实用的开源多功能原神工具箱 🧰 / Multifunctional Open-Source Genshin Impact Toolkit 🧰 项目地址: https://gitcode.com/GitHub_Trending/sn/Snap.Hutao…

📅 2026/8/20 20:33:56
MORE NEWS

更多资讯

📰

CS自学指南:从零补齐计算机基础的完整路线图

CS自学指南:从零补齐计算机基础的完整路线图 【免费下载链接】cs-self-learning 计算机自学指南 项目地址: https://gitcode.com/GitHub_Trending/cs/cs-self-learning CS自学指南是一本开源书籍,把 MIT、斯坦福、伯克利、CMU 等名校的顶级计算机…

📰

MeTube 自托管视频下载器:5 个问题快速上手

MeTube 自托管视频下载器:5 个问题快速上手 【免费下载链接】metube Self-hosted video downloader for YouTube and other sites (web UI for yt-dlp) 项目地址: https://gitcode.com/GitHub_Trending/me/metube MeTube 是一款自托管视频下载服务&#xff0…

📰

用 Planetary Computer Explorer 探索地球系统数据集:Data-Science-For-Beginners 第 20 课实战作业指南

用 Planetary Computer Explorer 探索地球系统数据集:Data-Science-For-Beginners 第 20 课实战作业指南 【免费下载链接】Data-Science-For-Beginners 10 Weeks, 20 Lessons, Data Science for All! 项目地址: https://gitcode.com/GitHub_Trending/da/Data-Scie…

📰

ADHD不是缺陷,是可编程的神经操作系统

1. 项目概述:这不是一个诊断标签,而是一份生活操作系统升级说明书“i-have-adhd”——短短五个单词组成的短语,最近在社交平台、创意社区和职场讨论区高频出现。它不是一句自嘲,也不是情绪宣泄,更不是对医学诊断的简单…

📰

✅ No Conflicts

✅ No Conflicts 【免费下载链接】Archon The first open-source harness builder for AI coding. Make AI coding deterministic and repeatable. 项目地址: https://gitcode.com/GitHub_Trending/archon3/Archon PR #{number} has no merge conflicts. Its ready for …

📰

SSM框架构建家电电商系统的核心技术解析

1. 项目概述:基于SSM的家用电器在线销售系统这个项目是一个典型的B2C电商平台,采用SSM(SpringSpringMVCMyBatis)框架技术栈实现。我在实际开发中发现,家电类电商系统相比普通商品销售平台有几个显著特点:商…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬