静态断言枚举是某种底层类型

Staticly assert that enum is a certain underlying type

MISRA 10.1 禁止对枚举类型的对象执行算术运算。

An operand of essentially enum type should not be used in an arithmetic operation because an enum object uses an implementation-defined integer type. An operation involving an enum object may therefore yield a result with an unexpected type. Note that an enumeration constant from an anonymous enum has essentially signed type.

他们还规定,++-- 一元运算符在本规则中被视为二元加法和减法。

如果我在循环控制结构中使用整数,我仍然需要稍后将它们转换回枚举,这将违反规则 10.5

The value of an expression should not be cast to an inappropriate essential type

有没有一种方法可以使用静态断言来保证关于底层枚举类型的某些假设?此代码将来可能会在其他架构上重用。在这种情况下,我想偏离 10.5,并确信如果违反了关于底层枚举类型的某些假设,代码将抛出编译时错误。

人为的例子:

enum {thing1, thing2, ... , thing_max } thing_index_t
...
for(int thing_index = 0; thing_index < (int) thing_max; ++thing_index)
{
    init_something((thing_index_t) thing_index);
    //             ^~~~~~~~~~~~~~~~~~~~~~~~~
    // cannot cast a signed value to an enum type
    // [MISRA 2012 Rule 10.5, advisory]
}

如果我静态断言 sizeof(thing_index_t == int);thing1 == 0u 对吧?

Int 将始终足够大以容纳我的整个值范围而无需提升 FWIW。

规则 10.5 总体上是合理的,但从 enum 到 signed/unsigned 的受控转换并不危险。 MISRA 担心的是您可能有一个像 enum {thing1=123, thing2=456, ... 这样的枚举。但是如果你知道枚举器常量是从 0 到最大值,那么使用 to/from 整数是最安全的。

您不需要针对建议规则的正式偏差。我宁愿发表评论,例如

/*  Violates MISRA 10.5 but iterating from thing1 to thing_num is safe. 
    Integer type is used since arithmetic on enums is forbidden by 10.1. */

(或使用您现有的任何流程来处理咨询规则。)


至于静态断言,sizeof(thing_index_t == int) 证明不了什么,因为允许的枚举常量值才是最重要的。 thing1 == 0u 由 C 标准保证,因此您无需断言。

确保枚举完整性的静态断言应该看起来像

#define THING_VALUES   \
  thing1,              \
  thing2,              \
  thing_num            \

typedef enum { thing1=123, thing2=456, thing_num } thing_index_t;
const size_t expected_size = sizeof((thing_index_t[]){ THING_VALUES }) / sizeof(thing_index_t);

_Static_assert( thing_num+1 == expected_size );

其中复合文字 (thing_index_t[]){ THING_VALUES }) 的大小对应于列表中枚举常量的数量。 expected_size 是项目数。这断言不存在特殊的初始化程序,例如 thing1=123

唯一的循环漏洞是像 thing1=123, thing2=1 这样的奇特的东西,它不会捕捉到。为了防止这种情况发生,您需要更进一步地使用宏,使用 X 宏等实现整个过程。