從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而不增加它?你也可以打印兩個字節並刪除所有疑問。 –