简体   繁体   English

运算符“ ++”的不允许操作数[MISRA 2012规则10.1,必填]

[英]Unpermitted operand to operator '++' [MISRA 2012 Rule 10.1, required]

I am trying to fix the Misra warning for the modules written by others. 我正在尝试为其他人编写的模块修复Misra警告。 I observed that ++ operation is being used on the enum . 我观察到在enum上使用了++操作。

I referred SE question which talks on the same topic. 我提到了关于同一主题的SE问题 How do I resolve this error? 如何解决此错误? Do I need to suggest the module owner, to change the implementation? 我是否需要建议模块所有者来更改实现?

#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;
}

I kept the enum like this in code purposefully to understand any impact. 我故意将这样的enum保留在代码中以了解任何影响。 However, in actual code, it is as below. 但是,在实际代码中,如下所示。

typedef enum
{  
        COMPARE,
        INCONSISTENT,
        WRITE,
        READ,
        FINISHED  
}TestsType;

Incrementing an enum is just wrong! 增加一个枚举是错误的!

enums were added to the language as a better alternative to #define for a number of constants, and were considered ints in other respects (ie a const array of ints). 枚举被添加到语言中,作为对#define的更好的替代,它包含多个常量,并且在其他方​​面也被视为int(即,int的const数组)。 To enforce anything more would require run-time checking. 要强制执行其他任何操作,都需要运行时检查。

As enum values don't have to be contiguous, incrementing them makes no sense when they're treated as integers. 由于枚举值不必是连续的,因此当将它们视为整数时,将它们递增是没有意义的。 If a compiler does allow it, it thinks it's incrementing an int, which can mean your value doesn't correspond to any value in the enum afterwards. 如果编译器确实允许它,它会认为它正在增加一个int,这可能意味着您的值此后与枚举中的任何值都不对应。

So my advice is "don't do it" even if a particular compiler lets you. 因此,即使特定的编译器允许您这样做,我的建议还是“不要这样做”。 Rewrite it to something explicit. 将其重写为明确的内容。

If you want to cycle through a particular range of states represented by contiguous integers, you CAN use an enum but only if you make its values contiguous too. 如果要循环显示由连续整数表示的特定状态范围,则可以使用枚举,但前提是必须使其值也连续。 Put lots of warnings about the definition explaining not to tinker. 在定义上放很多警告,以解释不要修改。 Then increment an int representing the state, which can then be compared to the enum safely. 然后增加一个表示状态的int,然后可以将其安全地与枚举进行比较。

The whole point of using a standard like MISRA is to avoid risky code . 使用诸如MISRA之类的标准的全部目的是避免风险代码 And there's no question but that incrementing enums is risky. 毫无疑问,但是增加枚举是有风险的。

If you've got some code that increments enums, and it works well (under all conditions), it's only because of a number of interlocked assumptions and conventions which probably aren't all written down and which almost certainly won't be obvious to (and honored by) a later maintenance programmer. 如果您有一些可以递增枚举的代码,并且在所有条件下都可以正常工作,那仅仅是因为有许多相互关联的假设和惯例,这些假设和惯例可能并没有全部写下来,并且几乎可以肯定不会(并得到后来的维护程序员的尊重)。

So, indeed, there is no simple fix for this. 因此,确实,没有简单的解决方案。 Any simple fix (which might get your MISRA checker to shut up) will likely leave the inherent risks in the practice all intact -- that is, you might satisfy the letter of MISRA, but not the spirit (which is obviously backwards). 任何简单的修复(可能会使您的MISRA检查器关闭)都可以保留实践中的固有风险,也就是说,您可能会满足MISRA的要求,但不能满足要求(显然是落后的)。

So yes, you should require (not just suggest) that the module owner change the implementation. 因此,是的,您应该(不仅仅建议)要求模块所有者更改实现。

What might the revised implementation look like? 修改后的实现会是什么样子? I think it should have one or more of the following aspects: 我认为它应该具有以下一个或多个方面:

  1. Use an int and some #define d constants. 使用一个int和一些#define d常量。
  2. Have a separate, encapsulated function to map from one state to the next. 有一个单独的封装函数,可以从一种状态映射到另一种状态。
  3. Use an explicit transition table to map one state to the next. 使用显式过渡表将一个状态映射到下一个状态。
  4. If there is a large number of states, and if most of them follow in sequence, such that a +1 increment would nicely encapsulate this (more cleanly and reliably than a bunch of arbitrary state transitions), go ahead and use a +1 increment, but with some accompanying assertions to ensure that the various assumptions hold. 如果存在大量状态,并且大多数状态依序进行,以致+1增量可以很好地封装该状态(比一堆任意状态转换更干净可靠),请继续使用+1增量, 附带一些断言以确保各种假设成立。 For example: 例如:
    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 */
        }
    }

The intent here is both to document what's going on, and ensure that if a later maintenance programmer changes the enum definition in any way that breaks the assumption that there are some consecutive states between which straight incrementation is allowed, the assertion will fail. 这样做的目的是记录发生的情况,并确保如果以后的维护程序员以任何方式改变枚举定义,从而破坏假定存在某些允许连续递增的连续状态的假设,则断言将失败。

...But I hasten to add that this is not a complete solution. ...但是我赶紧补充一点,这不是一个完整的解决方案。 An even more important guarantee to preserve is that every state transition is handled, and this is even easier to violate if a later maintenance programmer adds new states but forgets to update the transition mappings. 保留的一个更重要的保证是处理每个状态转换,而且如果以后的维护程序员添加新状态但忘记更新转换映射,则更容易违反。 One good way to have the compiler help you guarantee this is to use a switch statement, although this then just about forces you to make every transition explicit (that is, not to use the +1 shortcut): 让编译器帮助您保证这一点的一种好方法是使用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 ... ;
        }
    }

The advantage of using a switch is that modern compilers will warn you if you leave an enum value out of a switch like this. 使用switch的好处是,如果您在这样的开关中遗漏枚举值,现代编译器会警告您。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM