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

时间:2013-05-02 19:56:25

标签: 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) 

谢谢, 尼克

1 个答案:

答案 0 :(得分:2)

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

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


1)

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

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

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

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

// something.h

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

// something.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)

  

如何调用这样的函数?

flash_segment_erase(uint8_t * p_flash, uint16_t len);

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

C允许野生型演员的所有方式。你的代码的主要问题是你输出了const和volatile。

此外,您将把通用数据编程到闪存中。您的闪存编程驱动程序可能在字节级别上工作,但由于此原因,接口不必是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,不允许这些转换,也不允许在整数和指针之间转换。由于这些规则将有效地禁止CPU硬件寄存器,NVM编程,引导加载程序,MISRA-C的中断向量表,因此必须忽略它们。否则,MISRA-C不能在现实世界中使用。

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