【问题标题】:Why do bit fields in C need to be defined of type unsigned int or signed int [duplicate]为什么C中的位字段需要定义为无符号整数或有符号整数[重复]
【发布时间】:2014-06-02 04:32:48
【问题描述】:

我正在对我的 C 项目进行代码质量检查,该项目涉及带有位字段的结构。我遇到了一种情况,根据 MISRA C 2004 标准,规则 # 6.4 - 是违规行为,内容如下: “6.4 位字段只能定义为无符号整数或有符号整数类型。” Microsoft 开发人员网络here 上提供的文献断言了这一点。 谁能解释为什么位域成员的数据类型需要有符号或无符号整数?为什么我不允许执行以下操作,即使以下代码编译时不会出现警告:

typedef struct
{
    char a: 4;
    char b: 4;
    char flag: 1;
}MY_STRUCT

【问题讨论】:

  • 听起来像是可读性问题。大多数人不希望位域具有char 类型。
  • 您是标准委员会的成员。用成熟的标准语言解释当有人写 char x: 9 时会发生什么,以及为什么在 CHAR_BIT==8 的实现中。让其他委员会成员相信你的规则比他们的要好得多。不知道你,但对我来说这听起来像是浪费了一个周末。
  • 可能是因为 char 可以根据系统签名或不签名
  • @n.m.标准的相关部分是 §6.7.2.1 ¶4:指定位域宽度的表达式应为具有不超过该类型对象宽度的非负值的整数常量表达式如果省略了冒号和表达式,则将被指定。 除非 CHAR_BIT 至少为 9,否则 char x: 9 违反此要求。

标签: c structure bit-fields


【解决方案1】:

主要原因是如果你没有明确声明signedunsigned,你不知道该类型是否会被视为signedunsigned,除非通过阅读实现的定义确实如此。这意味着如果不使用带有显式签名关键字的类型,就无法编写可移植代码。 (也请注意,将char 用作位字段类型指示符是使用实现定义的类型。)

ISO/IEC 9899:2011 — §6.7.2.1 结构和联合说明符

位域的类型应为_Boolsigned intunsigned int 或其他一些实现定义的类型的合格或非合格版本。

位域被解释为有符号或无符号整数类型,包括 指定位数。125)

125)如上面 6.7.2 所述,如果使用的实际类型说明符是 int 或定义为 int 的 typedef-name, 那么位域是有符号还是无符号由实现定义。

指的是:

§6.7.2 类型说明符

¶4 指定位域宽度的表达式应是一个整数常量表达式,其非负值不超过指定类型的对象的宽度(如果省略冒号和表达式) .

¶5 ... 除了位域, 说明符 int 是否指定与 signed int 或与unsigned int 相同的类型。

【讨论】:

  • 感谢您的详尽回答。但是,我对数据类型(int 与 char)的选择比它的有符号或无符号更困惑。我的意思是,如果我只需要 4 位,那么使用 char 不是更有意义吗?此外,如果我要使用 memcpy 之类的库函数,则使用 chars 比 ints 更安全(以避免编译器隐式填充)。另外,对我来说,使用 int 会使代码的可移植性降低(如果有的话)。如果我错了,请纠正我,也许我遗漏了什么或误解了什么。
  • 标准只规定必须支持_Boolintunsigned intsigned int作为位域的类型;其他任何东西(charlong 等)都在实施时得到支持。使用char 不如int 可靠,但是(仅适用于位域),普通的int 可能意味着unsigned intsigned int,同样是在实现时的心血来潮。必须记录行为,但实现可以选择其中任何一个。因此,使用普通的int 不如signed intunsigned int 可移植;使用 char 而不是 int 也不太便携。
  • 请注意,charsigned charunsigned char 是不同的类型,但它的值范围与这两种类型之一相同。因此,简单的char 也可以根据实现的选择进行签名或无符号(但在位域上下文中的选择与实现中的其他任何地方相同)。
【解决方案2】:

标准不是我写的,只能推测。

也就是说,我的猜测是,当宽度实际上没有影响时(因为无论如何您都指定了位数),使用不同宽度的整数类型会令人困惑。例如:

char a : 4
short a : 4
int a : 4

所有声明的东西都是一样的,所以没有理由因为有不同的写法而造成混淆。

【讨论】:

  • 这些并不都声明相同的东西。如果 char/short/int/long long 是 8/16/32/64 位,那么一个有 21 个字段 char a:3 的类型将在 10 个字节的每个中打包两个,并将最后一个单独存储在一个字节中(11 个字节全部的);一个有 21 个 short a:3 类型字段的字段将五个放入四个短片中的每一个中,并将最后一个单独放入一个短片中(总共十字节);一个有 21 个 int a:3 类型的字段,每个字段将六个打包成两个 int,三个打包成第三个 int(总共 12 个字节); long long a:3 的 21 个字段将被放入一个 64 位值(总共 8 个字节)中。
猜你喜欢
  • 1970-01-01
  • 2022-01-20
  • 2013-09-01
  • 1970-01-01
  • 2012-01-09
  • 1970-01-01
  • 2016-02-17
相关资源
最近更新 更多