5

我很难理解关于位域(6.7.2.1:10)的一段 C99 草案标准(N1256)的确切含义:

6.7.2.1 结构和联合说明符

[...]

语义

[...]

实现可以分配任何大到足以容纳位字段的可寻址存储单元。如果有足够的空间,结构中紧跟在另一个位域之后的位域将被打包到同一单元的相邻位中。如果剩余空间不足,则将不适合的位域放入下一个单元还是与相邻单元重叠是实现定义的。单元内位域的分配顺序(高位到低位或低位到高位)是实现定义的。未指定可寻址存储单元的对齐方式。

强调的句子将我的英语技能发挥到了极限:我不明白它是指一个单元内的单个位域,还是指单个位域内的位排序或其他东西。

我会试着用一个例子让我的疑问更清楚。假设无符号整数是 16 位,实现选择无符号整数作为可寻址存储单元(并且字节为 8 位宽),并且不会出现其他对齐或填充问题:

struct Foo {
    unsigned int x : 8;
    unsigned int y : 8;
};

因此,假设xy字段存储在同一个单元内,那么根据那句话实现定义是什么?据我了解,这意味着在该 unsigned int 单元内部,x可以存储在低于y或反之亦然的低地址,但我不确定,因为直觉上我认为如果没有位字段与两个底层重叠存储单元,声明顺序将对底层位字段施加相同的顺序。

注意:我担心我在这里遗漏了一些微妙的术语(或者,更糟糕的是,一些技术术语),但我不明白是哪个。

任何指针表示赞赏。谢谢!

4

3 回答 3

7

我真的看不出有什么不清楚的地方

单元内位域的分配顺序(高位到低位或低位到高位)是实现定义的。

它讨论的是位域的分配,而不是域内的位。因此,除了非位域成员之外,您无法确定可寻址单元内的位域是按什么顺序排序的。

否则,位域本身的表示保证与底层类型“相同”,分为值位和符号位(如果适用)。

本质上,它表示包含位字段的存储单元的解剖结构是实现定义的,您不应该尝试通过其他方式(union或其他方式)访问这些位,因为这会使您的代码不可移植。

于 2013-09-06T10:30:13.063 回答
2

我的看法是,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 标准而言,它们都是合法的。

于 2013-09-06T07:54:44.610 回答
2

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 的 little-endian x86-64 CPU 上,输出为:

更改后a:0x00000001

更改 b 后:0x00000002

改c后:0x00000800

更改后 d: 0x80000000

由于这是一个联合,所以无符号整数(x)和位域结构(a/b/c/d)占用同一个存储单元。[the] 位域的分配顺序决定了 u.bits.a 是指 x 的最低有效位还是 x 的最高有效位。通常,在 little-endian 机器上:

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 编程语言不需要任何特定的字节序——大字节序和小字节序机器可以按照最适合其寻址方案的顺序放置数据。

于 2015-08-29T19:25:47.547 回答