1. bit field 介紹
位字段是乙個signed char、unsigned char、signed int、unsigned int 中一組相鄰的位。位欄位乙個結構宣告建立,該結構宣告為每個字段提供標籤,並決定欄位的寬度(位數)。以 int 型為例,如:
struct field; //共佔了8位
struct field field;
field.a = 1; //a = 01 (二進位制)
filed.b = 2; //b = 10 (二進位制)
filed.c = 3; //c = 11 (二進位制)
field.d = 3; //d = 011 (二進位制) 注意:賦值時不要超出欄位的容量,如:d的最大值為7(111)
變數 filed 被儲存在乙個int大小的儲存單元中,這個例子中僅有其中的八位被使用。
宣告的總位數超過乙個unsigned int 的大小,那將會使用下乙個unsigned int 儲存位置。不允許乙個字段跨越兩個unsigned int 之間的邊界。編譯器自動的移位乙個這樣的字段定義,使字段按unsigned int 邊界對齊。發生這種情況時,會在第乙個unsigned int 中留下乙個未命名的洞(unnamed hole )。
可以使用未命名的字段「填充」(pad)未命名的洞。
如果使用乙個寬度為 0 的未命名的字段,則迫使下乙個欄位與下乙個整數對齊。如:
struct field ;
注意:位字段是由機器依賴性的,即將字段放置到 int 中的順序。有些機器是從左向右(先使用高位),另一些機器是從右向左(先使用低位)。
在我的電腦上是從低位到高位的順序放置欄位的。下面的例子足以說明一切。
資料在記憶體中的存放方式是怎樣的?大端(big-endian)還是小端(little-endian)?呼叫函式時資料壓入棧、區域性變數在棧中分配空間的方式是怎樣的?下面的例子足以說明一切。
1)little-endian就是低位位元組排放在記憶體的低位址端,高位位元組排放在記憶體的高位址端。
2)big-endian就是高位位元組排放在記憶體的低位址端,低位位元組排放在記憶體的高位址端。
當然獲得cpu對記憶體採用big-endian還是little-endian的資料讀寫模式還有更簡單的辦法,後面的例子足以說明一切。
2. 下面的例子說明了一切
先看**:
#include int main(void)
field;
typedef struct char char;
int in = 0x13572468; //整型變數賦值,十六進製制
char ch; //char 型位字段變數
field field; //int 型位字段變數
int *add_ch, *add_ch_3; //指標 add_ch指向ch的位址,
//指標 add_ch_3指向比ch的位址小3個位元組單位的位址
ch.a = 15; //0xf
ch.b = 14; //0xe
field.a = 8; //0x8
field.b = 7; //0x7
field.c = 6; //0x6
field.d = 5; //0x5
field.e = 4; //0x4
field.f = 3; //0x3
field.g = 2; //0x2
field.h = 1; //0x1
add_ch = (int *)(&ch); //指標 add_ch指向ch的位址
add_ch_3 = (int *)(&ch - 0x03); //指標 add_ch_3指向比ch的位址小3個位元組單位的位址
printf("\nthe second byte \"24\" of the \"in = 0x13572468\" to char is \"%c\"\n",
*(((char *)(&in) + 0x1))); //列印in第二位元組的內容,如果沒有(char *),則整型指標加一是加四
//位元組單位的位址
printf("sizeof(in) = %d\n", sizeof in);
printf("sizeof(ch) = %d\n", sizeof ch);
printf("sizeof(field) = %d\n\n", sizeof field);
printf("&in = %p\n", &in); //in的位址
printf("&ch = %p\n", &ch); //ch的位址
printf("&field = %p\n\n", &field); //field的位址
printf("in = %#x\n", in);
printf("ch = %#x\n", ch);
printf("field = %#x\n\n", field); //十六進製制列印in、ch、field
printf(" add_ch_3 = (&ch - 0x03) = %p\n", add_ch_3);
printf("*add_ch_3 = *(&ch - 0x3) = %#x\n\n", *add_ch_3);
printf(" add_ch = %p\n", add_ch);
printf("*add_ch = %#x\n", *add_ch);
return 0;
}
再看輸出(除錯模式下):
從輸出結果中畫出記憶體棧,如下圖:
位址為0xbffff705處的位元組為0x24,其正好是字元 '$' 的ascii,因此程式的第一行列印出了 『$』 字元。從此處可以看出cpu對記憶體採用小端的讀寫模式。
把 ch 的位址0xffff703轉化成整型位址型別,列印此位址對應的值為 0x572468ef,其中高3個位元組是 in 值的低3個位元組。
標號 ①、②、③處的值為不確定的。
另外在執行main函式的過程中,按照宣告變數的順序把變數壓入棧中(在棧中依次為變數分配儲存空間)。
通過memory dump可以看出:
第一行中24對應的位元組值為'$'。
通過以上分析,所有問題一目了然。
下面通過更簡單的乙個例子獲得cpu對記憶體資料讀寫模式。
**如下:
#include int main(void)
c; c.a = 1;
if (c.b == 1)
printf("little-endian\n");
else
printf("big-endian\n");
return 0;
}
由於聯合體union的存放順序是所有成員都從低位址開始存放,利用該特性就可以輕鬆地獲得了cpu對記憶體採用little- endian還是big-endian模式讀寫。 談C 生僻知識點 位欄位(bit field)
位欄位允許使用者修改結構體中某個成員變數的特定位數,這種實現對於一般的程式似乎沒有什麼價值,但是對於硬體工程師來說,可以建立與特定硬體裝置上的暫存器對應的資料結構。同時,如果空間寶貴,資料型別儲存資料有空間冗餘,也可以使用位欄位優化。比如,c 中,bool型別僅儲存0或1,但是與char型別一樣佔1...
C C 中的位域 bit field
位域是c c 中常用的資料結構。在某些情況下合理的使用位域可以節省儲存空間,提高執行效率並提高程式的可讀行。按照我以往的程式設計經驗來看,通常以下情況下會優先考慮使用位域。1 有很多的狀態標記,需要集中儲存,比如tcp鏈結 的狀態 2 協議棧相關的資料結構,尤其是底層通訊協議中很多情況使用乙個或者幾...
C struct中的位域 bitfield
結構體的成員可以限制其位域,每個成員可以使用用比位元組還小的取值範圍,下面的結構體s1中,四個成員每個成員都是2bit的值 0 3 整個結構體佔據的空間依然是4個位元組,但是第乙個位元組中表示了四個成員,後續三個位元組沒有用到。struct s1 s1.a 1 s1.b 1 s1.c 1 s1.d ...