PAYATHON 2026

__const 和 __const__ 扩展关键字有什么区别?

技术老齐

作为类型限定符,两者没有区别

在 GCC 和 Clang 的 C、C++ 前端中,__const 和 __const__ 都是 const 的替代拼写。末尾的两个下划线不改变类型限定规则,也不提供额外的优化保证。Clang 扩展文档说明,这些拼写在所有语言模式下都可使用。

题目中关于 const 引入时间的说法需要纠正:它在 C89/C90 中就已经是标准关键字,并非 C99 才引入。GNU C 参考手册列出了 C89 的关键字。

为什么同时支持两种拼写?

带下划线的拼写是编译器扩展的一种命名方式。以两个下划线开头的名称属于实现保留的命名空间,编译器可以使用这些名称,避免占用普通程序可用的名称。__const 和 __const__ 都符合这一条件,尾部有没有下划线都一样。GCC 预处理器文档

这类替代拼写也方便头文件使用扩展。例如,某些严格标准模式会禁用普通拼写的 GNU 扩展关键字,__asm__、__inline__ 等形式则仍可使用。GCC 的替代关键字文档解释了这一用途。不过,const 本身早已是标准关键字,普通代码不需要为了严格标准模式而改用其他拼写。

保留两种形式可以兼容采用不同拼写的源码。Clang 的关键字定义也将它们归入 GCC 扩展。至于最初为什么同时引入这两种形式,上述文档和关键字定义没有说明确切的历史动机。

GCC 的关键字表直接体现了两者的等价关系:

{ "__const",   RID_CONST, 0 },
{ "__const__", RID_CONST, 0 },

两者映射到同一个 RID_CONST;Clang 也将两者注册为 const 的别名。GCC 关键字表、Clang 关键字表

代码中应该怎样选择?

  1. 新写的普通 C、C++ 代码直接使用标准拼写 const,便于阅读和跨编译器移植。
  2. 维护已有代码时,可以沿用项目的拼写习惯。如果准备改成 const,先确认相关头文件没有对这些名称做宏处理。

在 GCC 和 Clang 中,下面三个变量的类型都是 const int:

void example(void)
{
    const int a = 1;
    __const int b = 2;
    __const__ int c = 3;

    /* 取消任意一行注释,都会因修改只读变量而产生编译诊断。 */
    /* a = 4; */
    /* b = 4; */
    /* c = 4; */
}

指针声明中,限定符的位置也遵循相同规则:

__const int *p;       /* 等价于 const int *p */
int *__const__ q = 0; /* 等价于 int *const q = 0 */

p 可以重新指向其他对象,但不能通过 p 修改所指的 int;q 本身不能重新赋值。

注意适用范围

“所有语言模式下可用”指的是 GCC、Clang 的支持范围。ISO C 和 ISO C++ 并未要求所有编译器支持 __const 和 __const__,面向其他编译器的代码应优先使用 const。

两种拼写只有在编译器将它们解析为类型限定符时,语义才相同。预处理器仍将它们视为不同的名称;如果兼容层定义了相关宏,应先检查宏展开后的代码。

备注:内容仅供参考。