静态断言枚举是某个基础类型

时间:2019-01-22 20:52:45

标签: c enums c99 static-assert misra

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

  

本质上为枚举类型的操作数不应在算术运算中使用,因为   枚举对象使用实现定义的整数类型。涉及   因此,枚举对象可能会产生意外类型的结果。注意一个枚举   来自匿名枚举的常量具有基本已签名的类型。

他们还规定,出于该规则的目的,++--一元运算符被视为二进制加法和减法。

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

  

不应将表达式的值强制转换为不适当的值   基本类型

有没有一种方法可以使用静态断言来保证有关基本枚举类型的某些假设?此代码将来可能会在其他体系结构上重用。在这种情况下,我有信心偏离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。

1 个答案:

答案 0 :(得分:2)

规则10.5总的来说是声音,但是从enum到有符号/无符号的受控转换并不危险。 MISRA担心的是,您可能有一个像enum {thing1=123, thing2=456, ...这样的枚举。但是,如果您知道枚举数常量是从0到最大值,那么从整数访问/从整数访问是最安全的。

您不需要正式的咨询规则偏差。我宁愿留下

之类的评论
/*  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宏等实现整个过程。