一篇精巧的 C 语言编译器行为研究。当 C23 的 auto 关键字同时承担「存储类说明符」和「类型推断占位符」两种角色时,解析器面临歧义。如果外层作用域有一个同名的 typedef,auto x = 67; 应该声明一个推断类型的新变量(Clang 的做法),还是因为 x 被解析为类型名而报错(GCC 的做法)?文章揭示了 ANSI C 对此有明确的禁止条款,但 C23 标准对此保持沉默——这是一个罕见的、两大编译器行为不一致的标准灰色地带。
🔑 核心要点
C23 auto 的歧义:auto 既可以作为存储类说明符(auto x y)也可以作为类型推断占位符(auto x = 67),取决于上下文。
GCC vs Clang 分歧:当 typedef 与 auto 变量同名时,GCC 报错而 Clang 成功编译——两者对标准的解读不同。
ANSI C 的先见之明:ANSI C 明确规定在内部作用域不得省略 typedef 重声明时的类型说明符——C23 却删除了这一条款。
标准灰色地带:这是极为罕见的、C 标准未明确规定的语法歧义——两大编译器实现了不同行为且各有道理。
向前看的解析策略:Clang 通过前瞻(lookahead)判断 x 是类型名还是变量名,GCC 则采用更保守的即时绑定。