2014-01-16 244 views
0
void main() 
{ 
    struct bitfield 
    { 
     unsigned a:5; 
     unsigned c:5; 
     unsigned b:6; 
    }bit; 
    char *p; 
    struct bitfield *ptr,bit1={1,3,3}; 
    p=&bit1; 
    p++; 
    printf("%d",*p); 
} 



Explanation: 
  • 的= 1二進制值是00001(在5位)B的
  • 二進制值= 3是00011(在5位)
  • 二進制c = 3的值是000011(在6位)意外行爲

    我的問題是:在內存中它將如何表示爲?

當我編譯它給輸出12我無法弄清楚,爲什麼它的發生:在我看來,讓我們說內存中表示將在以下格式:

00001 000011 00011 
     |  | 
     501  500 (Let Say starting address) 

請糾正我,如果我我錯了。

+2

'void main()'! –

+0

什麼是'ptr'用於? – harper

+0

爲什麼不打印* p而不增加它?你也可以打印兩個字節並刪除所有疑問。 –

回答

1

實際表示是這樣的:

000011 00011 00001 
    b  c  a 

當作爲字節對齊:

00001100 01100001 
     |  | 
     p+1  p 

在地址(P + 1)是0001100其給出12.

1

C標準並未完全指定如何將位字段打包爲字節。細節取決於每個C實現。

選自C 2011 6.7.2.1:

11的實現可以分配任何可尋址的存儲單元大到足以容納一個位字段。如果剩餘足夠的空間,緊接在結構中的另一位字段之後的位字段應被打包到相同單元的相鄰位中。如果剩餘空間不足,則將不適合的位字段放入下一個單元或與相鄰單元重疊是實現定義的。位單元內的位字段的分配順序(從高位到低位或從低位到高位)是實施定義的。未指定可尋址存儲單元的對齊方式。

1

從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; 
}