即使通过指针分配,位域的大小也会被保存吗?

Will the size of bitfield be saved even if assigment is via pointer?

假设我有

struct foo
{
unsigned int bar : 7;
unsigned int next_field : 1;
}
void funct()
{
struct foo demo;
demo.next_field = 0;
unsigned char *barptr  = (unsigned char *)&demo;
/*1 = 00000001, bar can contain only 7 bits*/
*barptr = 1;
}

因为 bar 是 7 位而 char 是 8 位,会发生什么? bar 会用 0 填充并且 next_field 包含 1 吗? 结果会是:

0000000  1
|_____| |_|
  bar

0000001  0
|_____| |_|
  bar

或:

0000000  0
|_____| |_|
  bar

我会使用我的编译器进行检查,但我不知道这种行为是否是实现定义的,在 情况下,编译器可能会产生误导。

6.5.3.2 Address and indirection operators

The operand of the unary & operator shall be either a function designator, the result of a [] or unary * operator, or an lvalue that designates an object that is not a bit-field and is not declared with the register storage-class specifier.

您不能获取位域的地址。此操作在 C 中是非法的。

在这一点上,你正在相当残酷地跨越干净编程的边界。

unsigned char *barptr  = &foo.bar; /* first version of the question */
unsigned char *barptr  = (unsigned char *)&demo; /* after edit  */

您至少以两种方式使用了不是 char 的地址,并将其写入指向 char.

的指针

在那之后,使用该指针基本上会告诉编译器“这是一个字符。诚实。相信我。相信我。就写吧。”是否使用类型转换(两个版本之间的差异之一)实际上是无关紧要的。

*barptr = 1;

编译器之前的任何“知道位域的位大小”都被你之后公然向编译器撒谎。

如果你想通过指针干净地写 bar 这样做

struct foo *demop;
demop = &demo;
demop->bar = 1;

在 C 中,允许使用指向 unsigned char 的指针修改对象的字节。然而,由于位域的布局是实现定义的,因此它会产生什么值也是实现定义的。此外,成员 bar 在字节被修改之前没有被初始化,所以 anything 确实是可能的,包括假设它应该包含垃圾的编译器,即使包含 bar 成员的字节将由它初始化。

如果布局是大端,位域的后面的位甚至可能位于字节的 end 处,尽管不太可能,因此next_fieldbar 的值将完全不受更改的影响。

现在,你会用默认初始化器初始化它吗,

struct foo demo = {0};

之后
unsigned char *barptr  = (unsigned char *)&demo;
*barptr = 1;

我们可以说 barnext_field 可以设置一位,或者它们将完全归零;并且您必须检查编译器手册中的行为。例如,在 Linux 中,ABI documents 指定每个体系结构的位域布局。