宏定义中的Misra C错误
这段代码报告了三个misra c错误:宏定义中的Misra C错误,c,macros,misra,C,Macros,Misra,这段代码报告了三个misra c错误: 不适当的宏观扩张 类函数宏定义 不带括号的宏参数 原代码为: #define Wait(a, b) \ if (READ(b+0x1U)) \ { \ while ((a & Write(b))) \ {
#define Wait(a, b) \
if (READ(b+0x1U)) \
{ \
while ((a & Write(b))) \
{ \
/* Do nothing - Busy wait */ \
} \
}
Here READ(b) is a macro and Write(b) is a function with no Misra C error.
我正在尝试更改它以删除错误
#define Wait(a, b) \
if ((uint32_t)0U != READ((b)+0x1U)) \
{ \
while ((uint32_t)0U != ((uint32_t)(a) & Write((uint32_t)(b)))) \
{ \
/* Do nothing - Busy wait */ \
} \
}
但我仍然得到前两个错误。需要做些什么来删除这些Misra C错误。有一个宏可以扩展到的列表,其中不包括if块。我认为这是因为它可能会导致对附加else条款的混淆。您可以使用以下构造:
#define MACRO(X) \
do { \
body here \
} while (0)
只要有可能,就应该使用函数,而不是像宏这样的函数。在不知道READ扩展到什么的情况下,我不能说在这种情况下这是可能的。这将是摆脱这一警告的唯一途径
第三个你已经弄明白了;必须在正文中的a
和b
周围加括号。这里的想法是,如果您在宏中有类似于x*2
的代码,并且有人将3+1
作为x传递,不带括号,您将得到3+1*2
,即5,而不是(3+1)*2
,后者几乎肯定是8
关于您的代码,我唯一要说的是,您确定要&
而不是&
1.宏观扩张不当
这是因为您没有正确封装宏。要解决此问题,必须将代码更改为:
#define Wait(a, b) \
\
do { \
if (READ(b+0x1U)) \
{ \
while ((a & Write(b))) \
{ \
/* Do nothing - Busy wait */ \
} \
} \
} while (0);
(当然,如果代码的其余部分遵循MISRA-C并始终在每个if
、for
或while
语句之后使用{}
,那么这是毫无意义的练习。)
2.类函数宏定义 您正在使用类似宏的函数。MISRA-C不允许这样做。请将宏作为函数重写 然而,规则19.7是建议性的,所以理论上你可以忽略它而不引起偏差。但在这种情况下,没有理由这样做。没有理由认为这需要是一个宏而不是一个函数
3.不带括号的宏参数 正如您所猜测的,这与每个宏参数都是潜在的子表达式有关。假设有人将您的宏调用为
Wait(x+y,z)
。当遇到while循环时,您的代码将崩溃并烧掉,因为宏将扩展到while(x+y&Write(b))
,这与while(x+(y&Write(b))
相同
要解决此问题,请用括号括住a
和b
的每个实例,如第二个示例所示
这段代码报告了三个misra c错误: 你应该向Klockwork报告一个bug,因为他们的工具工作不正常。它还应该检测到以下情况:
违反规则13.2。符合MISRA的代码将是如果(读取(b+0x1U))
if (READ(b+0x1U) != 0u)
while ( (a & Write(b)) != 0u )
违反规则13.2。符合MISRA的代码将是while((a&Write(b))
if (READ(b+0x1U) != 0u)
while ( (a & Write(b)) != 0u )
非MISRA相关问题:
最好写为(uint32_t)0U
或0UL
,这是更可读的形式0UL
- 坦率地说,这段代码一开始就很糟糕。试图使其符合MISRA的现状,将使其变成一个完全无法阅读的混乱局面。改用从头重写:
void Wait (uint32_t a, uint32 b) { if( READ(b + 0x1u) != 0u ) /* comment here, explaining the code */ { while ( (a & Write(b)) != 0u ) /* comment here, explaining the code */ { ; /* Do nothing - busy wait */ } } }
if(x)Wait(a,b)那样调用它;else-foo()
您将得到一个语法错误,因为它扩展为if(x){…};否则…
,分号不可能在那里。使用do{…}while(0)
可以解决这个问题,因为while部分后面需要一个分号。@samueledwindward如果您编写与MISRA兼容的代码,这不是问题,因为MISRA会强制您在调用宏时编写If(x){Wait(a,b);}
。只有那些坚持在语句后跳过大括号的人才会遇到这种晦涩难懂的错误。@Lundin当然,但我认为值得花点力气来编写它,这样即使重用代码的人做了MISRA不赞成的事情,它也能正常工作。