MISRA-C编码标准解读:Rule 5.1至Rule5.7【标识符】
前言
在编程语言中用以区分和引用程序元素的基本构造单元被称为标识符名称,在软件开发中具有重要地位。遵循最佳实践有助于提升代码的可读性。本文参考MISRA-C手册探讨相关的命名规范,并在文末附上参考文献列表供查阅
规则 5.1(必须): 标识符(内部和外部)不应依赖于超过31个字符的意义
解释 : 此规则要求内部标识符(即在文件内部定义的标识符)必须在其前31个字符内保持唯一性,以确保代码的可移植性。该规则适用于所有命名空间,包括宏名,且31字符的限制在替换前后均适用。
注意 :易混淆的字符如1(数字一)与l(小写字母L)、0与O、2与Z、5与S、n与h应谨慎使用。
规则 5.2 (必须):在内层作用域中为标识符命名时应避免使用与外层作用域中已存在的相同名称,以避免暴露外层标识符
具体说明:‘外围作用域’特指那些位于文件级的标识符,在编程环境中通常用于全局范围内的变量声明或函数引用。“内部作用域”则特指那些嵌入于块层级之内的标识符,在函数体内或其他局部结构中使用。“内部动作领域”的存在会干扰到外围的作用机制,在某些情况下可能导致错误行为。如果在内部动作领域中涵盖了外围动作领域中的元素,则被视为违规操作。
示例 : 当引入第三方库时,在文档中明确列出该版本号,并应详细记录所有相关的验证测试结果。此外,请确保所选第三方库与MISRA-C标准完全兼容,并提供必要的验证证明材料。
int i; // 外层定义
{
int i; // 内层定义,隐藏了外层的i,不合规
i = 3; // 可能导致混淆,不清楚引用的是哪一个'i'
}
c
规则 5.3(必须): 类型定义名应当是一个唯一的标识符
解释: 该规则规定,在整个程序系统内必须为每个typedef命名提供一个独一无二的标识,并且不得重复使用同一个名称。即使出现在不同的源文件或包含头文件中也必须保证每个类型的名称都是唯一的。
示例 :
typedef unsigned char uint8_t; // 合规
// 下列均为不合规
typedef unsigned char uint8_t; // 重定义uint8_t
unsigned char uint8_t; // 重用uint8_t
c
规则 5.4(必须): 标签名应当是一个唯一的标识符
此规则规定,在程序中不得重复使用 struct 或 union 标签名,无论其用途是否涉及定义不同的标签或其他任何情况。当同一聚合类型声明在相同类型的限定符(struct或union)中使用相同标签时,C90标准对其行为未作明确说明。因此,在所有使用相同标签的地方必须统一采用 struct 类型限定符或统一采用 union 类型限定符。
示例 :
typedef unsigned char uint8_t; // 合规
// 下列均为不合规
typedef unsigned char uint8_t; // 重定义uint8_t
unsigned char uint8_t; // 重用uint8_t
c
规则 5.5(建议): 静态存储期的对象或函数标识符不应该被重用
对这一规则而言,“尽管它是一个建议性质的规定”,它明确指出无论作用域范围如何,“涉及任何带有静态存储特性的标识符(如包含外部链接的全局对象、函数或局部对象/函数)均不应在系统的任何源文件中被重复使用。”
第5.6条(建议):标识符在不同命名空间中不应具有相同的拼写(其中结构体成员和联合体成员的名称除外)。
解释 :此规则虽然为建议性规则,但提醒无论作用域如何,具有静态存储期的任何标识符(包括具有外部链接的全局对象或函数,以及使用静态存储类的局部对象或函数)都不应在系统的任何源文件中被重用.尽管编译器能够正确处理这种情况,但存在用户可能将同名但不相关变量错误地关联起来的风险,尤其是在一个文件中有内部链接的标识符,而在另一个文件中有同名的外部链接标识符.
struct { int16_t key; int16_t value; } record;
int16_t value; /* 违反规则 - value的第二次使用 */
record.key = 1;
value = 0; /* 应该是record.value */
c
相较于此例中所提到的情况而言,并未违反规定;因为结构体成员名称不容易造成误解:
struct device_q { struct device_q *next; /* ... */ }
devices[N_DEVICES];
struct task_q { struct task_q *next; /* ... */ }
tasks[N_TASKS];
devices[0].next = &devices[1];
tasks[0].next = &tasks[1];
c
规则 5.7(建议): 任何标识符名称都不应被重用
解释 : 该规则进一步明确了不论作用域如何均要求同一标识符不得在系统的所有文件中重复使用。其囊括了规则5.2至5.6的相关规定。举个例子来说,在结构体成员中也绝对不能重复使用同一标识符名称。
struct air_speed
{
uint16_t speed; /* knots */
} * x;
struct gnd_speed
{
uint16_t speed; /* mph */
/* 不合规 - 单位不同 */
} * y;
x->speed = y->speed;
c

在本例中,请注意尽管 speed 成员变量在两个不同的数据结构体中各自代表不同的物理量 然而使用相同的名称可能会导致理解上的混乱
参考文献 :MISRA-C手册
总结
通过防止同一模块内出现相同标识符名的同时,在整个系统范围内也禁止重复使用的标识符名(简称IDN),能够有效降低潜在错误与混淆的可能性,并显著提升代码的整体可读性和易维护性。例如在实际项目开发过程中遵循明确而具体的命名规范能够帮助实现上述原则。特别地 当某个IDN出现在包含该头文件的不同源文件中时 这些规定不会被视为违反
