不理解C标准中的位域描述

4
“字段是否可以跨越单词边界是由实现定义的。字段不必命名;未命名的字段(只有冒号和宽度)用于填充。特殊宽度0可用于强制在下一个单词边界处对齐。”
这句话来自 Kernighan & Ritchie所著《C程序设计语言》第二版第6.9节第150页,涉及IT技术相关内容。该句话解释了在C语言中如何使用字段对齐,表示字段是否可以跨越单词边界需要根据具体实现而定,同时未命名的字段可以用于填充。使用宽度为0的特殊字段可以强制在下一个单词边界处对齐。

你能提供一些关于这些代码行的上下文吗? - Salgar
可能是C语言规范。 - samoz
3个回答

8

"一个字段是否可以跨越词边界是由实现定义的。

考虑两个内存单元,其中字长为32位:

[31] [30] [29] ... [2] [1] [0] | [31] [30] [29] ... [2] [1] [0]

如果我们有一个结构体:
struct X
{
    int a : 30;
    int b : 4;
};

编译器可能会选择将字段b分成两部分,使其位于不同的字中,也可能留下空隙,使得整个b都在第二个字中:

[31] [30] [29] ... [2] [1] [0] | [31] [30] [29] [28] ... [2] [1] [0]
a--------------------a b-----------------b
OR
a--------------------a    GAP    b-----------------b

为什么会留下一个间隙?因为这样当它想要读或写b时,它只需要在内存中处理一个单词 - 这通常更快、更简单,需要更少的CPU指令。

字段不需要命名;未命名字段(只有冒号和宽度)用于填充。

如果我们改变之前的结构体,我们可以明确地要求一个间隙:

struct X
{
    int a : 30;
    int   : 2;  // unnamed field
    int b : 4;
};

这段话的意思是:“在a和b之间留下2个位 - 它们不需要标识符(名称),因为我永远不会询问它们的内容,也不需要要求更改它们的值”。但是,你不必只是为了让30 + 2 == 32(我们的字长)而将其设置为2,你可以请求任何你喜欢的间隔。如果您正在处理来自某些硬件设备的值,并且您知道其中一些位,但不知道其他位,或者您只是不需要使用其中一些位-您可以仅将它们命名为空以记录您的不感兴趣,同时仍然使编译器将命名的位字段间隔在所需的偏移量内,以对应于硬件的使用。

特殊宽度0可以用于强制对齐到下一个字边界。”

这意味着编译器可以计算出部分填充的字中剩余了多少位,并跳到下一个字的开头。就像我们通过添加上面的2位字段(给定a为30位和字长为32)确保b从新的字开始一样,我们也可以...
struct X
{
    int a : 30;
    int   : 0;  // unnamed field
    int b : 4;
};

...编译器将为我们计算出2。这样,如果我们将a更改为其他大小,或者最终编译为64位字大小,编译器将自动调整适当的行为,而无需手动更正未命名字段。


非常感谢您提供这个精彩而清晰的答案,并配有图示。 - Abhishek Ghosh

1

基本上,如果一个地址是“字对齐”的,处理器可以更快地执行操作。一个字通常是32位或4字节。

典型处理器是“字”对齐的,这意味着它们可以在一次操作中检索整个内存“字”。当一个值跨越多个值时,处理器必须执行多个操作才能获取相同的数据。有时,这是不可避免的,例如如果您使用一个“双字”,但如果您有一个单个字跨越一个字边界,CPU将不得不执行2个操作来检索单个字的数据。

一个字对齐值的例子是0x10000004、0x10000008。由于一个字是4字节,地址必须是4的倍数。一个非字对齐值是0x10000003。

对于程序员来说,所有操作都会按预期工作,但在底层,CPU必须执行1个内存操作来读取或写入到0x10000004,而它必须执行2个内存操作来读取或写入到0x10000003,因为它跨越了一个字边界。

关于您最初的问题,基本上是说根据您使用的编译器,编译器可能会或可能不会对您的字段进行字对齐。这是大小与速度的例子,如果您不进行字对齐,可以打包更多数据,但如上所示,它将变得更慢。

0

首先,这主要与内存“对齐”有关。编译器通常会将变量或字段对齐到字边界上,32位平台上一个字是32位。这意味着两个布尔值将成为不同单词中的第一个字节,而不是连续的两个字节。

位域可以强制在内存中进行布局:如果其值范围为0-7,则可以确保特定字段仅使用3位。

字段可以没有名称。如果您不打算使用它,则不需要命名字段。这可以用于强制特定的布局。

如果使用:0,它将自动对齐到下一个字边界。

一般来说,除非以某种方式调整性能,否则不需要此行为。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接