我很难理解C99标准草案(N1256)关于位域(6.7.2.1:10)的确切含义:
6.7.2.1结构和联合说明符
[...]
语义
[...]
实现可以分配足够大的任何可寻址存储单元来保存位字段。如果剩余足够的空间,则紧跟在结构中的另一个位字段之后的位字段将被打包到相同单元的相邻位中。如果剩余的空间不足,则是否将不适合的位域放入下一个单元或重叠相邻单元是实现定义的。 单元内位域(高位到低位或低位到高位)的分配顺序是实现定义的。 对齐可寻址存储单元未指定。
强调的句子将我的英语技能提升到极限:我不明白它是指单元内的各个位字段,还是单个位字段内的位排序或其他内容。
我会试着通过一个例子让我更加清楚。假设无符号整数是16位,实现选择unsigned int作为可寻址存储单元(并且字节宽度为8位),并且不会出现其他对齐或填充问题:
struct Foo {
unsigned int x : 8;
unsigned int y : 8;
};
因此,假设x
和y
字段存储在同一单元内,那么根据该句子实现定义的是什么?据我了解,这意味着在无符号int单元内,x
可以存储在低于y
的地址,反之亦然,但我不确定,因为直觉上我是认为如果没有位字段与两个底层存储单元重叠,则声明顺序将对底层位字段强加相同的顺序。
注意:我担心我在这里遗漏了一些术语(或者更糟糕的是,一些技术性的),但我无法理解它。
任何指针都赞赏。谢谢!
答案 0 :(得分:6)
我真的没有看到
的不清楚单元内位域分配的顺序(高位到 低阶或低阶到高阶)是实现定义的。
它讨论了位字段的分配,而不是字段内的位。因此,除了非位字段成员之外,您无法确定可寻址单元内的位字段的排序顺序。
否则,位字段本身的表示保证与基础类型“相同”,并且分为值位和符号位(如果适用)。
本质上它说包含位字段的存储单元的解剖结构是实现定义的,你不应该试图通过其他方式(union
左右)来访问这些位,因为这会使你的代码不可移植。
答案 1 :(得分:1)
我的看法是,C99规范讨论的是位字段的位端,以及它们是如何以“单位”(字节字等)排序的。如果你开始施放结构,基本上你就是你自己。
实施例
bit ex1 ex2 ex3
D7 x3 y0 x0
D6 x2 y1 x1
D5 x1 y2 x2
D4 x0 y3 x3
D3 y3 x0 y0
D2 y2 x1 y1
D1 y1 x2 y2
D0 y0 x3 y3
以上三种不同的方案,用于对字节“单元”中的两个4位字段进行排序。就C99标准而言,所有这些都是合法的。
答案 2 :(得分:1)
Gibbon1的回答是正确的,但我认为示例代码对这类问题很有用。
#include <stdio.h>
int main(void)
{
union {
unsigned int x;
struct {
unsigned int a : 1;
unsigned int b : 10;
unsigned int c : 20;
unsigned int d : 1;
} bits;
} u;
u.x = 0x00000000;
u.bits.a = 1;
printf("After changing a: 0x%08x\n", u.x);
u.x = 0x00000000;
u.bits.b = 1;
printf("After changing b: 0x%08x\n", u.x);
u.x = 0x00000000;
u.bits.c = 1;
printf("After changing c: 0x%08x\n", u.x);
u.x = 0x00000000;
u.bits.d = 1;
printf("After changing d: 0x%08x\n", u.x);
return 0;
}
在使用MinGW&GCC的小端x86-64 CPU上,输出为:
更改后:0x00000001
更改b:0x00000002
后更改c:0x00000800
后更改d:0x80000000
后
由于这是一个联合,因此unsigned int(x)和位字段结构(a / b / c / d)占用相同的存储单元。 [em]位域的分配顺序决定u.bits.a是指x的最低有效位还是x的最高有效位。通常,在小端机器上:
u.bits.a == (u.x & 0x00000001)
u.bits.b == (u.x & 0x000007fe) >> 1
u.bits.c == (u.x & 0xeffff800) >> 11
u.bits.d == (u.x & 0x80000000) >> 31
并在大端机器上:
u.bits.a == (u.x & 0x80000000) >> 31
u.bits.b == (u.x & 0x7fe00000) >> 21
u.bits.c == (u.x & 0x001ffffe) >> 1
u.bits.d == (u.x & 0x00000001)
标准所说的是C编程语言不需要任何特定的字节序 - 大端和小端机器可以按照其寻址方案最自然的顺序放置数据。