比特域的类型是什么?

R..*_*R.. 16 c language-lawyer bit-fields c11

我在C标准中找不到指定的任何地方.例如,在

struct { signed int x:1; } foo;
Run Code Online (Sandbox Code Playgroud)

foo.x一个类型的左值int,还是其他什么?int因为你不能在其中存储任何类型的值int,只有0或-1,但它找不到任何类型的语言,这似乎是不自然的.当然,在大多数表达式中使用它,int无论如何它都会被提升,但是实际的类型在C11中有所不同_Generic,而且我在标准中找不到任何关于位域如何与之交互的语言_Generic.

Jen*_*edt 5

正如Jonathan所引用的那样,p5清楚地说明了比特字段的类型.

您还应该记住的是,6.3.1.1中的位域算术转换有一个特殊规则,基本上说明如果一个int可以表示所有值,那么位字段将转换int大多数表达式.

a中的类型_Generic应该是声明的类型(以符号小故障为模),因为似乎是算术转换不适用的共识.所以

_Generic((X), int: toto, unsigned: tutu)
_Generic(+(X), int: toto, unsigned: tutu)
Run Code Online (Sandbox Code Playgroud)

如果X是无符号位域,其宽度具有所有值,则可以给出不同的结果int.


Jon*_*ler 3

鉴于您包含了signed限定符,那么可以存储在 1 位位字段中的唯一值确实是 -1 和 0。如果您省略了限定符,则将由实现定义“普通”位int字段是否为已签名或未签名。当然,如果您指定了unsigned int,则值将为 0 和 +1。

\n\n

该标准的相关章节是:

\n\n
\n

\xc2\xa76.7.2.1 结构和联合说明符

\n\n

\xc2\xb64 指定位域宽度的表达式应为具有非负值的整数常量表达式,该值不超过由冒号和表达式指定的类型的对象的宽度省略。122)如果值为零,则声明不应有声明符。

\n\n

\xc2\xb65 位字段的类型应为_Boolsigned\n intunsigned int或某些其他实现定义的类型的限定或非限定版本。是否允许原子类型是由实现定义的。

\n\n

\xc2\xb610 位字段被解释为具有由指定位数组成的有符号或无符号整数类型。125)如果值 0 或 1 存储到类型 的非零宽度位字段中_Bool,则该位字段的值应等于存储的值;\n 位字段_Bool具有 a 的语义_Bool

\n\n

122)虽然对象中的位数_Bool至少为CHAR_BIT,但 a 的宽度(符号和值位数)_Bool可能仅为 1 位。

\n\n

125)如上面 6.7.2 中指定的,如果使用的实际类型说明符是int或定义为 的 typedef-name int,则无论位域是有符号还是无符号,它都是实现定义的。

\n
\n\n

脚注125指出:

\n\n
\n

\xc2\xa76.7.2 类型说明符

\n\n

\xc2\xb65 每个逗号分隔的多重集都指定相同的类型,除了位域之外,\n 说明符是否int指定与\n 相同的类型 signed int还是与 相同的类型是实现定义的unsigned int

\n
\n

  • 在你的例子中,它的类型是“signed int”,不是吗?如果您指定了(普通)“int”,则该类型将由实现定义。但类型是位域声明中指定的类型。如果您指定了“_Bool”,则为“_Bool”,否则为您指定的任何整数类型。我不确定我是否遗漏了什么或者你过度思考(或两者兼而有之)。 (3认同)
  • 我没有问值的范围。我问左值是什么类型。这对于它如何与“_Generic”交互以及其他晦涩的方式(如“?:”运算符怪异)交互很重要。 (2认同)
  • 我只是对这样的概念感到有点困扰,即您可以拥有一个“int”类型的左值,但它不能用于忠实地存储和检索“int”类型的任何值。从概念上讲,似乎类型应该是“宽度为 1 的有符号位域”或类似的,但 C 没有这样的“类型”,所以我认为左值的类型确实是 `int`... (2认同)