[英]Unpermitted operand to operator '!' [MISRA 2012 Rule 10.1, required]
[英]Unpermitted operand to operator '++' [MISRA 2012 Rule 10.1, required]
我正在尝试为其他人编写的模块修复Misra警告。 我观察到在enum
上使用了++
操作。
我提到了关于同一主题的SE问题 。 如何解决此错误? 我是否需要建议模块所有者来更改实现?
#include <stdio.h>
typedef enum
{
COMPARE = 0,
INCONSISTENT = 10,
WRITE,
READ,
FINISHED
}TestsType;
static TestsType CurrentTest;
void fun1(void)
{
if(READ != CurrentTest)
{
CurrentTest++;
}
else
{
CurrentTest = FINISHED;
}
}
int main(void) {
// your code goes here
CurrentTest = COMPARE;
fun1();
printf("%d", CurrentTest);
return 0;
}
我故意将这样的enum
保留在代码中以了解任何影响。 但是,在实际代码中,如下所示。
typedef enum
{
COMPARE,
INCONSISTENT,
WRITE,
READ,
FINISHED
}TestsType;
增加一个枚举是错误的!
枚举被添加到语言中,作为对#define的更好的替代,它包含多个常量,并且在其他方面也被视为int(即,int的const数组)。 要强制执行其他任何操作,都需要运行时检查。
由于枚举值不必是连续的,因此当将它们视为整数时,将它们递增是没有意义的。 如果编译器确实允许它,它会认为它正在增加一个int,这可能意味着您的值此后与枚举中的任何值都不对应。
因此,即使特定的编译器允许您这样做,我的建议还是“不要这样做”。 将其重写为明确的内容。
如果要循环显示由连续整数表示的特定状态范围,则可以使用枚举,但前提是必须使其值也连续。 在定义上放很多警告,以解释不要修改。 然后增加一个表示状态的int,然后可以将其安全地与枚举进行比较。
使用诸如MISRA之类的标准的全部目的是避免风险代码 。 毫无疑问,但是增加枚举是有风险的。
如果您有一些可以递增枚举的代码,并且在所有条件下都可以正常工作,那仅仅是因为有许多相互关联的假设和惯例,这些假设和惯例可能并没有全部写下来,并且几乎可以肯定不会(并得到后来的维护程序员的尊重)。
因此,确实,没有简单的解决方案。 任何简单的修复(可能会使您的MISRA检查器关闭)都可以保留实践中的固有风险,也就是说,您可能会满足MISRA的要求,但不能满足要求(显然是落后的)。
因此,是的,您应该(不仅仅建议)要求模块所有者更改实现。
修改后的实现会是什么样子? 我认为它应该具有以下一个或多个方面:
int
和一些#define
d常量。 enum state {
OFF = 0,
LOW = 3,
MEDIUM,
HIGH,
EXCEPTIONAL = 10
};
/* States LOW..HIGH are assumed to be contiguous. Make sure you keep them so! */
/* If (and only if) you add or subtract states to the contiguous list, */
/* make sure to also update N_CONTIGUOUS_STATES. */
#define N_CONTIGUOUS_STATES 3
enum state nextstate(enum state oldstate)
{
/* Normally performing arithmetic on enums is wrong. */
/* We're doing so here in a careful, controlled, constrained way, */
/* limited just to the values LOW..HIGH which we're calling "contiguous". */
assert((int)LOW + N_CONTIGUOUS_STATES - 1 == (int)HIGH);
if(oldstate >= LOW && oldstate < HIGH) {
return (enum state)((int)oldstate + 1);
} else {
/* perform arbitrary mappings between other states */
}
}
这样做的目的是记录发生的情况,并确保如果以后的维护程序员以任何方式改变枚举定义,从而破坏假定存在某些允许连续递增的连续状态的假设,则断言将失败。
...但是我赶紧补充一点,这不是一个完整的解决方案。 保留的一个更重要的保证是处理每个状态转换,而且如果以后的维护程序员添加新状态但忘记更新转换映射,则更容易违反。 让编译器帮助您保证这一点的一种好方法是使用switch
语句,尽管这将迫使您明确每个转换(即,不使用+1快捷键):
enum state nextstate(enum state oldstate)
{
switch(oldstate) {
case OFF: return ... ;
case LOW: return MEDIUM;
case MEDIUM: return HIGH;
case HIGH: return ... ;
case EXCEPTIONAL: return ... ;
}
}
使用switch
的好处是,如果您在这样的开关中遗漏枚举值,现代编译器会警告您。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.