“字段是否可以重叠单词bounday是实现定义的。字段不需要命名;未命名的字段(仅冒号和宽度)用于填充。特殊宽度0可用于强制对齐下一个字边界。“
我无法获得这些线条。你能解释一下吗?
答案 0 :(得分:6)
“字段是否可能与单词bounday重叠是实现定义的。
考虑两个内存字,其中字大小为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
为什么会留下GAP?因为当它想要读取或写入b时,它只需要在内存中使用一个字 - 这通常更快更简单,需要更少的CPU指令。
字段无需命名;未命名的字段(仅限冒号和宽度)用于填充。
如果我们改变了早期的结构,我们可以明确地要求一个空白:
struct X
{
int a : 30;
int : 2; // unnamed field
int b : 4;
};
这就是说“在a和b之间留下2位 - 它们不需要标识符(名称),因为我永远不会问它们中有什么,或者需要询问它们的值是否被改变”。但是,你不必只是为了30 + 2 == 32(我们的字号)......你可以随心所欲地找到你喜欢的任何空白。如果您正在处理来自某些硬件设备的值,并且您知道某些部分是什么而不是其他部分,或者您只是不需要使用其中的某些部分,那么这可能很有用 - 您可以将它们保留为未命名的文档你仍然不感兴趣,同时仍然在编译空间中将所需的偏移量中的命名位字段转换为与硬件用法相对应的字。
特殊宽度0可用于强制在下一个字边界处对齐。“
这只是意味着编译器可以计算部分填充的字中剩余的位数,并跳到下一个字的开头。正如我们通过在上面添加一个2比特字段确保b开始于一个新单词(假设我们知道a是30位且字大小为32),我们可以...
struct X
{
int a : 30;
int : 0; // unnamed field
int b : 4;
};
...编译器会为我们计算出2。这样,如果我们将a更改为其他大小,或者最终编译为64位字大小,编译器将静默调整为适当的行为,而无需手动更正未命名的字段。
答案 1 :(得分:1)
基本上,如果地址是“字对齐”,则处理器可以更快地执行操作。字通常为32位,或4字节。
典型的处理器是“字”对齐的,这意味着它们可以在一次操作中检索整个“字”的内存。当值跨越多个值时,处理器必须执行多个操作才能获得相同的数据。有时,这是不可避免的,例如,如果您使用“双字”但如果您有一个单词跨越字边界,则CPU将必须执行2次操作以检索单个数据字。
字对齐值的示例是0x10000004,0x10000008。由于一个字是4个字节,因此地址必须可被4整除。非字对齐值为0x10000003。
对程序员来说,所有操作都会按预期工作,但是在引擎盖下,CPU必须执行1次内存操作才能读取或写入0x10000004,而它必须执行2次内存操作才能读取或写入0x10000003,因为它跨越了字边界。
在提到您的原始问题时,这基本上是说根据您使用的编译器,编译器可能会或可能不会对您的字段进行对齐。这是大小与速度的示例,因为如果没有对齐,可以打包更多数据,但如上所示,它会更慢。
答案 2 :(得分:0)
首先,它主要与记忆'对齐'有关。编译器通常在字边界上对齐变量或字段,在32位平台上字是32位。这意味着两个bool将在不同单词的第一个字节之间,而不是两个连续的字节。
位字段可以强制在内存中布局:如果特定字段的值范围为0-7,则可以确定特定字段仅使用3位。
字段可以是未命名的。如果您不打算使用它,则无需为字段命名。这可用于强制特定布局。
如果您使用:0
,它将自动对齐下一个字边界。
通常,除非您以某种方式调整性能,否则不需要此行为。