MISRA C 2012违反规则11.4

hzbexzde  于 2023-08-03  发布在  其他
关注(0)|答案(3)|浏览(168)

面对与MISRA C 2012规则11.4违反有关的问题。使用PC-Lint Plus进行规则检查。Keil uVision V5.38.0.0
错误代码:

conversion between object pointer type 'GPIO_Type *' and integer type 'unsigned int' [MISRA 2012 Rule 11.4, advisory]```
uint *L_uc_byte = (uint *)&GPIO->PIN[0];

字符串
以下是与GPIO相关的详细信息

#define     __IO    volatile             /*!< Defines 'read / write' permissions */
/** Peripheral GPIO base address */
#define GPIO_BASE                                (0x4008C000u)
/** Peripheral GPIO base pointer */
#define GPIO                                     ((GPIO_Type *)GPIO_BASE)

/** GPIO - Register Layout Typedef */
typedef struct {
  __IO uint8_t B[6][32];                           /**< Byte pin registers for all port 0 and 1 GPIO pins, array offset: 0x0, array step: index*0x20, index2*0x1 */
       uint8_t RESERVED_0[3904];
  __IO uint32_t W[6][32];                          /**< Word pin registers for all port 0 and 1 GPIO pins, array offset: 0x1000, array step: index*0x80, index2*0x4 */
       uint8_t RESERVED_1[3328];
  __IO uint32_t DIR[6];                            /**< Direction registers, array offset: 0x2000, array step: 0x4 */
       uint8_t RESERVED_2[104];
  __IO uint32_t MASK[6];                           /**< Mask register, array offset: 0x2080, array step: 0x4 */
       uint8_t RESERVED_3[104];
  __IO uint32_t PIN[6];                            /**< Port pin register, array offset: 0x2100, array step: 0x4 */
       uint8_t RESERVED_4[104];
  __IO uint32_t MPIN[6];                           /**< Masked port register, array offset: 0x2180, array step: 0x4 */
       uint8_t RESERVED_5[104];
  __IO uint32_t SET[6];                            /**< Write: Set register for port Read: output bits for port, array offset: 0x2200, array step: 0x4 */
       uint8_t RESERVED_6[104];
  __O  uint32_t CLR[6];                            /**< Clear port, array offset: 0x2280, array step: 0x4 */
       uint8_t RESERVED_7[104];
  __O  uint32_t NOT[6];                            /**< Toggle port, array offset: 0x2300, array step: 0x4 */
       uint8_t RESERVED_8[104];
  __O  uint32_t DIRSET[6];                         /**< Set pin direction bits for port, array offset: 0x2380, array step: 0x4 */
       uint8_t RESERVED_9[104];
  __O  uint32_t DIRCLR[6];                         /**< Clear pin direction bits for port, array offset: 0x2400, array step: 0x4 */
       uint8_t RESERVED_10[104];
  __O  uint32_t DIRNOT[6];                         /**< Toggle pin direction bits for port, array offset: 0x2480, array step: 0x4 */
} GPIO_Type;


我试过很多方法
1.

conversion between object pointer type 'GPIO_Type *' and integer type 'unsigned int' [MISRA 2012 Rule 11.4, advisory]
uint data = ( ( GPIO->PIN[0] >> 17U ) & 0x03U );


1.

conversion between object pointer type 'uint *' (aka 'unsigned int *') and integer type 'volatile uint32_t' (aka 'volatile unsigned int') [MISRA 2012 Rule 11.4, advisory]
volatile uint L_uc_byte = *( uint * )(GPIO->PIN[0]);


1.

conversion between object pointer type 'GPIO_Type *' and integer type 'unsigned int' [MISRA 2012 Rule 11.4, advisory]
uint L_uc_byte = GPIO->PIN[0];


1.使用地址文字作为指针

conversion between object pointer type 'uint *' (aka 'unsigned int *') and integer type 'unsigned int' [MISRA 2012 Rule 11.4, advisory]
uint L_uc_byte = *( uint * )( 0x40002000U + 0x2100U);

需要解决方案来解决此规则冲突。

yhuiod9q

yhuiod9q1#

  • 你需要从你的代码库中删除那个奇怪的uint类型--不要发明奇怪的非标准的、非自文档化的整数类型。使用标准C uint32_t
  • 请注意,最好避免将volatile限定表达式(例如阅读/写寄存器)与其他操作数或子表达式(以及另一个MISRA违规)混合。这对性能目的和清晰度不利,并且额外的副作用可能会给予不可预测的结果。尝试使寄存器访问表达式只执行写或读操作,而不执行其他操作。
  • 除非您对C有深入的了解,否则不要执行指针转换强制转换。将一个整数转换为一个没有volatile限定的uint*是永远不正确的。特别是,它几乎肯定永远不是正确的路线去的情况下,你得到警告。
  • 不应该使用像x >> 17 & 42这样的“魔术数字”,因为它们使代码不可读,并迫使读者坐在那里,鼻子一直埋在MCU手册的寄存器描述中。使用有意义的名字。如果您使用的是MCU供应商提供的寄存器Map,则它通常带有可供使用的命名常量。

详情如下:How to access a hardware register from firmware?
此外,MISRA-C有一些过于迂腐的建议规则,并不真正适用于嵌入式系统。其中一条规则禁止整数和指针之间的转换,但是没有办法在不执行这种类型转换的情况下定义寄存器Map,因此必须忽略该规则。
MISRA的关键是理解 * 为什么 * 他们首先制定了规则。这种情况下的主要问题是对齐,像uint32_t* data = (uint32_t*)0x0003;这样的东西会导致指针不对齐。如果你明白为什么这是一个严重的错误,那么你就明白为什么MISRA制定了这个规则。如果您不打算提供任何类似的自制地址,则可以安全地忽略该规则。
标准的做法是,跳过咨询规则不需要正式的偏离。尽管理想情况下,基于MISRA的编码标准应该列出所有可以忽略的建议规则,然后在静态分析器/MISRA检查器中相应地禁用它们。
结论:
uint data = ( ( GPIO->PIN[0] >> 17U ) & 0x03U );更改为uint32_t data并将常量命名为有意义的名称。理想情况下,为了符合MISRA,您还应该将其拆分为几个表达式,这有点过分,但应该100%符合MISRA:

uint32_t data = GPIO->PIN[0]; // volatile expression as a stand-alone read/write

// just making up some names here, refer to the MCU manual for proper names:
data = (data >> GPIO_POS ) & GPIO_MASK;

字符串
如果忽略整数到指针的建议规则,我们应该这样做:

#define SOME_REGISTER (*(volatile uint32_t*)(0x40002000U + 0x2100U))
...
uint32_t L_uc_byte = SOME_REGISTER;

kyxcudwk

kyxcudwk2#

如果您计划在多个位置使用GPIO,则至少可以在单个位置发生MISRA违规。
创建一个如下的peripherl.h文件:

extern GPIO_Type * const GPIO;

字符串
创建如下所示的peripheral.c文件:

#include "peripheral.h"

#define GPIO_BASE (0x4008C000u) // define as needed
#define ADC_BASE  (0x4008D000u) // define as needed

// add your MISRA tool comment/pragma here
// this should be the only place of violating the rule
GPIO_Type * const GPIO = (GPIO_Type*)GPIO_BASE;
ADC_Type  * const ADC  = (ADC_Type*)ADC_BASE;


现在,您可以在代码中使用GPIO指针,而不会发生这种冲突;
main.c

#include "peripheral.h"

int main(void) {
    // since the GPIO is defined in header as GPIO_Type*
    // and initialized in peripheral.c, there should be
    // no violation here
    uint32_t x = (GPIO->PIN[0] >> 17u) & 0x3u;
    
    return 0;
}

h6my8fg2

h6my8fg23#

MISRA承认,某些指南可能会对合法用例造成问题......这就是为什么我们创建了偏差流程,如MISRA Compliance中所述。
同样,对于咨询指南(如R.11.4),这些可以 * 不适用 *。
R.11.4甚至包括(在基本原理中)一个声明,大意是在寻址内存Map寄存器 * 时可能需要违反此规则 *。
因此,正确的方法(除了Lundin的优秀建议之外)不是忽略R.11.4,而是(有正当理由)不适用它
--联系方式见个人资料

相关问题