带(有符号)枚举值的按位运算

Bitwise operation with (signed) enum value

我正在为标志使用枚举器值:

typedef enum
{
    a = 0x00,
    b = 0x01u, // the u has no influence, as expected
    c = 0x02u, // the u has no influence, as expected
...
} enum_name;

volatile unsigned char* reg = SomeAddress;
*reg |= b;

根据 MISRA-C:2004,不应使用有符号类型进行按位运算。不幸的是,我的编译器 IAR 使用 signed int(或 short 或 char)作为枚举的基础类型,我能找到的唯一选项与大小有关,而不是符号(“--enum -is-int").

基础类型是有符号还是无符号并不重要,前提是您只对枚举使用正值,因为正值应该与有符号或无符号类型具有相同的表示形式。标准在 6.2.6.2 Representation of types/Integer types §5 中说:A valid (non-trap) object representation 符号位为零的有符号整数类型是 相应的无符号类型,应表示相同的值。

因此,如果您愿意,您可以安全地转换为 unsigned。无论如何,如果底层类型是 char(或者是 unsigned char),它可以在任何计算之前(静默地)提升为 int。

恕我直言,MISRA-C:2004 表示不应使用有符号类型进行位运算,因为标准明确表示负数的表示是实现定义的:

对于有符号整数类型,对象表示的位应分为三 组:值位、填充位和符号位。不需要任何填充位;应该只有一个符号位......如果符号位是一个,值应该是 通过以下方式之一修改:

  • 符号位0对应的值取反(符号和大小);
  • 符号位的值为-(2N)(二进制补码);
  • 符号位的值为 -(2N - 1)(个的补码)。

  • 其中哪些应用是实现定义的(强调我的)

TL/DR :如果你没有警告(并且你不应该为 | 按位或)你可以安全地完全不使用强制转换。如果您将正值转换为无符号类型,表示不变,因此如果您(或您的公司规则)选择遵循 MISRA-C,您也可以进行转换,因此您也可以安全地转换为无符号类型

根据 IAR C/C++ Development Guide for ARM,第 169 和 211 页,如果您启用 IAR 语言扩展(-e 命令行选项,您可以定义 enum 的类型,或 项目 > 选项 > C/C++ 编译器 > 语言 > 允许 IDE 中的 IAR 扩展

特别是,您应该定义一个额外的 "sentinel" 值,以确保编译器选择正确的类型。它更喜欢有符号类型,并使用尽可能小的整数类型,因此标记应该是相应无符号整数类型可以描述的最大正整数。例如,

typedef enum {
    /* ... */
    enum_u8_sentinel = 255U
} enum_u8;

typedef enum {
    /* ... */
    enum_u16_sentinel = 65535U
} enum_u16;

typedef enum {
    /* ... */
    enum_u32_sentinel = 4294967295UL
} enum_u32;