保留标识符
C 标准把一部分标识符保留给实现和标准库使用。用户代码若声明或定义这些名字,轻则触发诊断,重则进入未定义行为。这个约束不是“命名洁癖”,而是为了避免与你的编译器、运行库或系统头文件发生符号冲突。
1. 常见保留规则
以一个下划线加大写字母开头(如 _IOBUF)或以两个下划线开头(如 __size)的名字,总是保留给实现。以单个下划线开头、但具有外部链接的名字,也属于保留范围。除此之外,标准库头文件公开的外部标识符同样不能被用户重新定义。
2. 一个对比例子
/* 不推荐:可能与实现冲突 */
int __count = 0;
int _Engine = 0;2
3
运行结果:该代码块主要用于语法或结构说明,单独运行通常无终端输出。
/* 推荐:普通项目命名 */
int engine_count = 0;
int mdr_engine_state = 0;2
3
运行结果:该代码块主要用于语法或结构说明,单独运行通常无终端输出。
如果需要统一命名前缀,优先使用项目缩写加下划线,而不是借用保留前缀。这样做不仅可移植,也能减少与第三方库链接时的符号碰撞。
3. 头文件中的额外注意
当你包含某个标准头文件后,标准允许实现在该名字空间中引入更多内部标识符。稳妥做法是:在公共接口层坚持自定义前缀,不使用以下划线开头的外部名称,并避免定义与标准库同名的宏。
4. 一条可执行的命名策略
对项目级公共接口,可以固定使用“项目前缀 + 语义名”的形式,例如 mdr_parser_init、mdr_token_kind。这种策略的价值不只在可读性,更在于它几乎天然避开保留标识符规则,且在多库链接时更不易发生符号碰撞。
5. 宏命名也应遵守同样规则
很多冲突并不来自函数名,而来自宏名。公共头文件里的宏若使用过于通用的短名字,容易与第三方库或系统头发生替换冲突。稳妥做法是给宏也加统一前缀,例如 MDR_,并把可见范围限制在确有必要的公共接口层。
6. 一致性检查思路
对公共头文件做一次命名扫描,重点筛查以下模式:以下划线起始的外部标识符、与标准库接口同名的宏、无项目前缀的全局可见符号。把这三类收敛后,符号冲突风险通常会显著下降。
7. 文件作用域下划线前缀的误区
有些代码会把“以下划线开头”当作模块私有约定,但这并不等于标准允许。尤其在文件作用域,以下划线开头的标识符很容易落入保留范围。更稳妥的做法是使用显式项目或模块前缀,例如 mdr_、lexer_,并通过 static 控制可见性,而不是依赖特殊前缀制造“私有感”。
8. 头文件中的宏防护命名
头文件保护宏同样应避开保留模式。像 __FOO_H__ 这类写法虽然常见,但属于高冲突命名。建议改成 FOO_H 或带项目前缀的 MDR_FOO_H。这样既满足防重包含目的,也不会和实现保留空间重叠。