C标准库头文件预留非下划线开头非标准标识符是否为可接受实践?
问题解答
你的理解是否正确
你对C11标准7.1.3节的理解完全没有偏差。C11标准明确规定仅以下几类标识符属于预留范围,用户不能自行定义:
- 所有以下划线开头、后接大写字母或另一个下划线的标识符,在所有作用域预留
- 所有以下划线开头的标识符,在文件作用域作为普通标识符、标签名预留
- 标准库公开的所有宏名,只要你包含了对应的头文件就预留
- 标准库中具有外部链接的标识符,无论是否包含对应头文件,在所有作用域预留
- 标准库中在对应头文件声明的非宏、非外部链接标识符,只要你包含了对应头文件,就在同命名空间(普通/标签/结构体成员)预留
你引用的标准原文内容:
No other identifiers are reserved.
确实意味着CLK_TCK、NL_NMAX、STRUNCATE这类既不在标准规定的公开标识符列表、也不符合下划线开头预留规则的标识符,理论上完全对终端用户开放,用户有权定义使用。
为什么标准库会定义这类标识符
这类标识符几乎都是历史遗留的扩展兼容产物:
CLK_TCK是最早的POSIX.1-1990标准规定的宏,后来虽然被_SC_CLK_TCK替代,但glibc为了兼容几十年前的旧代码,一直保留了该定义NL_NMAX是POSIX扩展定义的limits类常量,属于POSIX对C标准的扩展内容,Cygwin为了兼容POSIX程序保留了该定义STRUNCATE是微软CRT早期的扩展定义,作为_TRUNCATE的兼容别名保留,适配老版本MSVC编写的代码
这类实践是否合规
严格按照ISO C标准的要求,这类在用户开放命名空间定义非标准标识符的行为确实不符合标准要求。
但这是行业内普遍接受的兼容实践:实现方为了保证存量旧代码能正常编译,不会轻易删除已经存在了十几年甚至几十年的扩展定义。几乎所有C标准库实现都提供了关闭这类扩展的编译选项:
- GCC/Glibc环境下,定义
_ANSI_SOURCE宏、或者使用-std=c11而非-std=gnu11编译,会自动屏蔽大部分非标准宏的暴露 - MSVC环境下的
/Za选项就是用来关闭微软扩展,只是部分历史过于悠久的宏没有和该选项绑定,避免破坏过多存量代码
内容的提问来源于stack exchange,提问作者pmor
相关产品推荐
相关产品推荐

