我正在嵌入式 C 脚本中执行指针赋值,如下所示:
uint32_T *a = (uint32_T *) (4096U);
基本上,我需要a
指向地址位置4096(十进制(
我收到标题中指定的 MISRA 警告(我使用 Code Composer Studio 的 MISRA C:2004 检查器(。
如何修复此警告?
PS:uint32_T
是unsigned long
的typedef
这是一种 MISRA-C 规则,不要太认真对待它本身 - 该规则是建议性的,主要是为了迫使程序员在做一些有潜在危险的事情之前三思而后行并学习。
整数到指针的转换存在许多缺陷:
- 对准。
- 指针和整数之间的大小或表示形式不同。
- 陷阱表示形式,包括硬件异常和无效地址。
- 类型兼容性问题和严格的指针别名。
普通程序员通常不知道上述所有内容。如果不是,这种整数到指针的转换可能是危险的。
您必须事先知道指向的地址是有效的,并且使用选择的类型取消引用它是有意义的。例如,如果您知道该内存地址处有一个 32 位硬件寄存器,则完全可以通过uint32_t*
指针取消引用。
您还必须知道给定系统的指针格式。在 32 位系统上,它们通常只是 32 位地址。在较小的系统(如 8/16 位 CPU(上,您可能有不同的指针类型,大小在 16 到 24 到 32 位之间,使事情变得更加复杂。
摘要:如果您知道自己在做什么,则可以忽略此咨询 MISRA-C 规则。
代码的其他问题:
- 不要使用自制的整数类型,使用 stdint.h。如果您坚持使用 C90,请定义与 stdint.h 中同名的类型并使用这些类型。
- 从内存地址转换为指针而不使用
volatile
几乎可以肯定是错误的。编译器不知道那里存储了什么,如果您不volatile
限定指针,可能会做出奇怪的假设和不正确的优化。如果是硬件寄存器或 NVM 内存,它可能随时更改,并且也必须因此volatile
。
更正后的代码应为:volatile uint32_t *a = (volatile uint32_t*)4096U;
我在一个非常禁止这样的演员的环境中工作,这正是MISRA追求的原因。
然而,在特定领域,这种转换非常普遍,并且遵循特定目的(即访问内存映射外围,特别是在嵌入式微控制器等环境中(。
我已经设法让所有相关方(上级、质量工程、需求工程等(同意该规则基本上适用并应遵守,但对于确切的特殊区域,由于必要,它是允许的。也就是说,我
得到了一个"空白通行证"来忽略这些警告,并享受决定何时的信任,前提是我记录了它。当然,这也意味着在其他情况下不要忽略它。
因此,这并没有解决如何在代码中修复它的问题,但它确实回答了如何在MISRA代码检查器是制作公认软件的相关部分的环境中避免麻烦的问题。
该规则有一个相当好的理由 - 除了直接处理内存映射寄存器之外,这是一个非常有效的规则。
但MISRA自己也意识到,偶尔需要违反规则......这就是为什么我们有一个偏差过程,记录在MISRA合规性中。
事实上,在内存映射寄存器的特定实例中,我们甚至创建了一个许可证来帮助偏差。目前只有MISRA C:2004的许可证,但将在2012年适当的时候发放。