即使通过指针分配,位域的大小也会被保存吗?
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_field
和 bar
的值将完全不受更改的影响。
现在,你会用默认初始化器初始化它吗,
struct foo demo = {0};
之后
unsigned char *barptr = (unsigned char *)&demo;
*barptr = 1;
我们可以说 bar
或 next_field
可以设置一位,或者它们将完全归零;并且您必须检查编译器手册中的行为。例如,在 Linux 中,ABI documents 指定每个体系结构的位域布局。
假设我有
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 theregister
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_field
和 bar
的值将完全不受更改的影响。
现在,你会用默认初始化器初始化它吗,
struct foo demo = {0};
之后
unsigned char *barptr = (unsigned char *)&demo;
*barptr = 1;
我们可以说 bar
或 next_field
可以设置一位,或者它们将完全归零;并且您必须检查编译器手册中的行为。例如,在 Linux 中,ABI documents 指定每个体系结构的位域布局。