c - MISRA04 将 typedef 结构指针转换为 int 指针

标签 c pointers casting msp430 misra

我正在为 MSP430F5438A 编写一些固件。我希望这段代码主要是 MISRA04 投诉(我使用的是 C99,而不是 C90)。我正在使用 IAR 5.51,它可以检查 MISRA 合规性。

我有以下数据结构:

typedef struct
{
    struct
    {
        uint16_t baud_rate;
        uint8_t data_bits;
        uint8_t parity;
        uint8_t stop_bits;
        uint8_t b_flow_control;
    } serial_settings;
    ...
} config_settings_t;

我想在闪存中创建一个可以全局读取的结构实例。我已经有单独的方法来写入闪存。

这是指向该结构的全局指针的定义:

volatile config_settings_t *gp_app_config = (uint8_t) 0x1800u;

这工作正常并且似乎符合 MISRA 要求。

现在,我在闪存驱动程序中实现了一组函数,可以对闪存中的任意段进行写入和读取。它们都以 uint8_t 指针作为参数。

如何调用这样的函数?

flash_segment_erase(uint8_t * p_flash, uint16_t len);

这个:

flash_erase_check((uint8_t*)gp_app_config, sizeof(config_settings_t));

编译并工作正常,但根据 MISRA04 是禁忌...

Error[Pm141]: a cast should not be performed between a pointer to object type and a different pointer to object type, this casts from type "config_settings_t volatile *" to "uint8_t *" (MISRA C 2004 rule 11.4) 

谢谢, 尼克

最佳答案

考虑使用 MISRA-C:2012,因为它支持 C99。我不知道 IAR 是否支持它,MISRA-C:2012 已于今年 Spring 早些时候发布。

对于 MISRA-C:2004,有几件事需要考虑。


1)

  • 声明全局变量接近 MISRA-C 合规性。有两条规则,8.10 和 8.11,强制文件范围变量为静态“除非需要外部链接”。在你的情况下是否需要是有点主观的。没有明显的理由说明为什么您需要该指针是全局的。

  • 你将闪存的指针声明为读写指针,这很奇怪。这没有任何意义。

  • 将地址转换为指向 uint8_t 的指针是没有意义的,而您实际上想要一个指向 config_settings_t 的 const volatile 指针。此外,规则 11.5 禁止丢弃 const 或 volatile 关键字。

    因此,我会考虑在使用它的模块内将其声明为静态,并使其只读。考虑像这样重写代码:

//某事.h

const volatile config_settings_t* get_app_config (void); 
// use a getter function instead of a global variable

//某事.c

static const volatile config_settings_t *
  gp_app_config = (const volatile config_settings_t*) 0x1800u;


const volatile config_settings_t* get_app_config (void)
{
  return gp_app_config;
}

还要考虑将实际指针本身存储在 ROM 中(是的,这会使该声明读起来更加“邪恶”......):

static const volatile config_settings_t * const
  gp_app_config = (const volatile config_settings_t*) 0x1800u;

2)

How can I call a function like this?

flash_segment_erase(uint8_t * p_flash, uint16_t len);

你不应该。首先,这是 NVM 编程驱动程序的一部分,因此它将始终处理只读变量。将它们声明为 volatile 可能没有必要,但在某些编译器上它可以使您避免优化器事故。

C 允许各种方式的野生型强制转换。您的代码的主要问题是您抛弃了 const 和 volatile。

此外,您还将把通用数据编程到闪存中。您的闪存编程驱动程序可能在字节级别工作,但接口(interface)不必是 uint8_t* 仅仅因为这一点。将其更改为 void* 将挽救局面,并使您免受 MISRA 规则 11.2 的影响。

您应该将函数声明为:

void flash_segment_erase (const volatile void* p_flash, uint16_t len);

现在您有了一个 const volatile config_settings_t* 并且您希望将其传递到采用通用 const volatile void* 参数的函数中。这应该完全兼容 MISRA。


3)

请注意,sizeof 生成 size_t 类型的变量,该变量不一定与 uint16_t 完全兼容。例如,如果 size_t 等于 uint32_t,您将违反各种 MISRA 规则。因此,转换为表达式的预期类型:

flash_erase_check (gp_app_config, (uint16_t)sizeof(config_settings_t));

编辑:有各种简单的愚蠢规则,例如 11.3 和 11.4,它们不允许像这样的强制转换,也不允许在整数和指针之间进行强制转换。由于这些规则将有效地禁止来自 MISRA-C 的 CPU 硬件寄存器、NVM 编程、引导加载程序、中断 vector 表,因此必须忽略它们。否则,MISRA-C 无法在现实世界中使用。

显然,这些规则是一些桌面程序员或工具供应商的结果,没有任何嵌入式编程经验,对委员会的影响太大了(咳-ldra-咳)。尽管有许多 MISRA 用户提示,但 MISRA-C:2012 中仍然存在同样愚蠢的建议规则。

关于c - MISRA04 将 typedef 结构指针转换为 int 指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16346623/

相关文章:

c - 如何在c中正确释放()我的malloc

c - 如何在C中扫描最多10^18位的数字

c - 如何在 C 中优化这段代码

将指针转换为整数

c - 当我尝试从 C 程序调用已编译的 NASM 函数时出现 undefined reference 错误

C++ 指向 unordered_map 条目的指针发生变化,但条目没有

c++ - 使用 char* 存储整数

C++ 意外隐式转换

php - Casting 在 PHP 中如何工作?

c++ - 分配对指针数组的引用