如何解决 MISRA C:2012 规则 11.6?

How to resolve MISRA C:2012 Rule 11.6?

我正在利用 Microchip 示例 nvmem.c 文件功能将数据写入 PIC32 微控制器的特定内存地址。当我尝试使用它时显示以下 MISRA 错误:我刚刚在出现错误的地方发布了示例代码。我的整个代码已编译并运行良好。

1] explicit cast from 'unsigned int' to 'void ' [MISRA 2012 Rule 11.6, required] at NVMemWriteWord((void)APP_FLASH_MARK_ADDRESS,(UINT)_usermark);

我该如何解决这个错误?

nvmem.c
uint8_t NVMemWriteWord(void* address, uint32_t data)
{
    uint8_t res;
    NVMADDR = KVA_TO_PA((uint32_t)address); //destination address to write
    NVMDATA = data;
    res = NVMemOperation(NVMOP_WORD_PGM);
}

test.c
#define ADDRESS 0x9D007FF0U;
NVMemWriteWord((void*)ADDRESS,(uint32_t)_usermark);

使用

uint8_t NVMemWriteWord(unsigned int  address, uint32_t data)
{
    uint8_t res;
    NVMADDR = KVA_TO_PA(address);
    NVMDATA = data;
    res = NVMemOperation(NVMOP_WORD_PGM);
}

#define  ADDRESS  0x9D007FF0U

NVMemWriteWord(ADDRESS,(uint32_t)_usermark);

相反。在功能上它与示例完全相同,它只是避免了从 void 指针到无符号整数地址的转换。

关于指针转换的整个 MISRA-C:2012 第 12 章非常挑剔。这是正确的,因为这是非常危险的领域。

11.6 是一个健全的规则,禁止从整数到 void* 的转换。基本原理是阻止对齐错误。无论如何,您想要进行此类转换的原因并不多。

值得注意的是,还有两个严格但建议性的规则 11.4 禁止从整数到指针的转换,以及 11.5 几乎完全禁止使用 void*。不可能进行与硬件相关的编程并遵循 11.4,因此必须忽略该规则。但是你没有理由使用 void*.

在这个特定的转换中,您可以通过使用 uint32_t 并完全避免指针来逃脱。

在寄存器访问的一般情况下,必须使用volatile限定指针进行转换:(volatile uint32_t*)ADDRESS,假设MCU使用32位寄存器。

建议:

#define ADDRESS (volatile uint32_t*)0x9D007FF0U
NVMemWriteWord( ADDRESS, _usermark) ;

从不强制转换为 void* - void* 的目的是您可以安全地将任何其他指针类型分配给它,而无需显式强制转换。 _usermark 的转换可能是必要的,也可能不是必要的,但是应该避免不必要的显式转换——它们可以抑制重要的编译器警告。您应该按照以下优先顺序进行类型转换:

  • 类型协议 - 完全相同的类型。
  • 类型兼容性 - 较小的类型到较大的类型,相同的符号。
  • 类型大小写 - 最后的手段(例如,从大到小的类型、符号不匹配、整数 to/from 指针)。

在这种情况下,由于 NVMemWriteWord 只是将 address 转换为整数,因此使用 void* 可能不合适。如果在其他上下文中您实际上使用的是指针,那么它可能是有效的。