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

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

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”)。

根据IAR C / C ++开发指南(适用于ARM) ,第169和211页,如果启用IAR语言扩展( -e命令行选项或项目 > 选项 > C / C ++编译器) ,则可以定义enum的类型。 > 语言 > 允许在IDE中使用IAR扩展

特别是,您应该定义一个额外的“sentinel”值,以确保编译器选择正确的类型。 它更喜欢有符号类型,并使用尽可能小的整数类型,因此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; 

如果您只为枚举使用正值,则基础类型是否为无符号类型无关紧要,因为正值应与有符号或无符号类型具有相同的表示forms。 标准说明6.2.6.2类型/整数类型的表示§5: 符号位为零的有符号整数类型的有效(非陷阱)对象表示是相应无符号类型的有效对象表示,并应表示相同的价值。

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

恕我直言,MISRA-C:2004表示bitwize操作不应该使用有符号类型,因为标准明确表示负数的表示是实现定义的:

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

  • 符号位0的相应值被否定(符号和幅度);
  • 符号位的值为 – (2N)(二进制补码);
  • 符号位的值为 – (2N – 1)(1’补码)。

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

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