从C11标准(6.7.2.1):
比特连接的视场的分配单位(高位到低位或低阶到高阶)内的顺序是实现定义的。未指定可寻址存储单元的对齐方式。
我知道一个事实,即在类Unix系统GCC和其它编译器命令,可以从操作系统源的IP报头的定义来证明在主机字节顺序位字段我不得不派上用场:
struct ip {
#if _BYTE_ORDER == _LITTLE_ENDIAN
u_int ip_hl:4, /* header length */
ip_v:4; /* version */
#endif
#if _BYTE_ORDER == _BIG_ENDIAN
u_int ip_v:4, /* version */
ip_hl:4; /* header length */
#endif
其他编译器可能也这样做。由于你很可能在一台小型机器上,所以你的位域将从你期望的位置向后(除了已经倒退的位置)。很可能它在内存中看起来像这样(请注意,在你的问题中,你的字段在结构中的顺序是“a,c,b”,而不是“a,b,c”,只是为了使这更容易混淆):
01100001 00001100
| |
byte 0 byte 1
| | | |
x a b c
所以,所有三位字段都可以填充到一个int中。填充是自动添加的,它位于所有位字段的开始位置,它放在字节2和3处。然后b
从字节1的最低位开始。在c
之后它开始于字节1 2,但我们只能放入两个它的位,c
的两个最高位是0,然后c
继续在字节0(x
在我上面的图片),然后在那之后你有a
。
请注意,图片的字节和左边的位都是最低的地址向右增长(这在文献中非常标准,您的图片在一个方向上有位,在另一个方向上有字节使得一切都变得更加令人困惑,特别是增加了字段“a,c,b”的奇怪排序。
我没有上述的任何感运行这个程序,然后在字节顺序读了起来:
#include <stdio.h>
int
main(int argc, char **argv)
{
unsigned int i = 0x01020304;
unsigned char *p;
p = (unsigned char *)&i;
printf("0x%x 0x%x 0x%x 0x%x\n", (unsigned int)p[0], (unsigned int)p[1], (unsigned int)p[2], (unsigned int)p[3]);
return 0;
}
然后,当你明白什么小端做的字节顺序在一个int,地图你的比特场,但场后向。然后它可能会开始有意义(我已经这么做了很多年,但仍然令人困惑)。
另一个例子来说明位字段如何向后两次,一次是因为编译器决定把他们向后一小端机器上,然后再次因为整数的字节顺序:
#include <stdio.h>
int
main(int argc, char **argv)
{
struct bf {
unsigned a:4,b:4,c:4,d:4,e:4,f:4,g:4,h:4;
} bf = { 1, 2, 3, 4, 5, 6, 7, 8 };
unsigned int *i;
unsigned char *p;
p = (unsigned char *)&bf;
i = (unsigned int *)&bf;
printf("0x%x 0x%x 0x%x 0x%x\n", (unsigned int)p[0], (unsigned int)p[1], (unsigned int)p[2], (unsigned int)p[3]);
printf("0x%x\n", *i);
return 0;
}
'void main()'! –
什么是'ptr'用于? – harper
为什么不打印* p而不增加它?你也可以打印两个字节并删除所有疑问。 –