位域,pragma pack n 相關

2021-04-16 09:54:16 字數 4262 閱讀 1502

裡面有如下**:

struct i;

for (i.a = 1; i.a <= 9; i.a++)

for (i.b = 1; i.b <= 9; i.b++)

if (i.a % 3 == i.b % 3)

printf(「a = %d, b = %d/n」, i.a, i.b);

不解,到網上搜尋一下,原來是位域相關問題。

有些資訊在儲存時,並不需要占用乙個完整的位元組, 而只需佔幾個或乙個二進位制位。例如在存放乙個開關量時,只有0和1 兩種狀態,用一位二進位即可。為了節省儲存空間,並使處理簡便,c語言又提供了一種資料結構,稱為「位域」或「位段」。所謂「位域」是把乙個位元組中的二進位劃分為幾個不同的區域,並說明每個區域的位數。每個域有乙個網域名稱,允許在程式中按網域名稱進行操作。 這樣就可以把幾個不同的物件用乙個位元組的二進位制位域來表示。一、位域的定義和位域變數的說明位域定義與結構定義相仿,其形式為:

struct 位域結構名

; 其中位域列表的形式為: 型別說明符 位網域名稱:位域長度

struct bs

int a:8;

int b:2;

int c:6;

};對於位域的定義尚有以下幾點說明:

struct bs bit,*pbit;

bit.a=1;

bit.b=7;

bit.c=15;

printf("%d,%d,%d ",bit.a,bit.b,bit.c);

pbit=&bit;

pbit->a=0;

pbit->b&=3;

pbit->c|=1;

printf("%d,%d,%d ",pbit->a,pbit->b,pbit->c);

上例程式中定義了位域結構bs,三個位域為a,b,c。說明了bs型別的變數bit和指向bs型別的指標變數pbit。這表示位域也是可以使用指標的。程式的9、10、11三行分別給三個位域賦值。( 應注意賦值不能超過該位域的允許範圍)程

序第12行以整型量格式輸出三個域的內容。第13行把位域變數bit的位址送給指標變數pbit。第14行用指標方式給位域a重新賦值,賦為0。第15行使用了復合的位運算子"&=",該行相當於:pbit->b=pbit->b&3位域b中原有值為7,與3作按位與運算的結果為3(111&011=011,十進位制值為3)。同樣,程式第16行中使用了復合位運算"|=", 相當於:pbit->c=pbit->c|1其結果為15。程式第17行用指標方式輸出了這三個域的值。

使用位域的主要目的是壓縮儲存,其大致規則為:

1)  如果相鄰位域字段的型別相同,且其位寬之和小於型別的sizeof大小,則後面的字段將緊鄰前乙個字段儲存,直到不能容納為止;

2)  如果相鄰位域字段的型別相同,但其位寬之和大於型別的sizeof大小,則後面的字段將從新的儲存單元開始,其偏移量為其型別大小的整數倍;

3)  如果相鄰的位域字段的型別不同,則各編譯器的具體實現有差異,vc6採取不壓縮方式,dev-c++採取壓縮方式;

4)  如果位域字段之間穿插著非位域字段,則不進行壓縮;

5)  整個結構體的總大小為最寬基本型別成員大小的整數倍。

#include

#pragma pack(1)

using namespace std;

int main()

; struct s

;cout<

system("pause");

return 0;

}在這裡bs總共占有 4+3+1 byte

4: sizeof(int)

3: for the alignment

1: sizeof(char)

位域是將c乙個型別的變數分開(提供乙個分開操作某種資料型別的機制,使操作粒度到達bit級別)管理如果把上面程式中第二行的注釋去掉

則bs總共占用 4+1 byte

4: sizeof(int)

//3: alignment every 1 byte according to the #pragma pack(1), so this blank is removed.

1: sizeof(char)

這裡給出struct s最為對比

注釋掉pack指令

sizeof(s) = 4+4+4+4+2+2 = 20 byte

加上pack指令

sizeof(s) = 4+4+4+4+1+1 = 18 byte

那麼#pragma pack()的具體含義如何呢?

簡單的說:

#pragma pack(n)

資料邊界對齊方式:

以如下結構為例: struct

在windows預設結構大小: sizeof(struct) = 4+4+4+4=16;

與#pragma pack(4)一樣

若設為 #pragma pack(1), 則結構大小: sizeof(struct) = 1+2+4+1=8;

若設為 #pragma pack(2), 則結構大小: sizeof(struct) = 2+2+4+2=10;

在#pragma pack(1)時:空間是節省了,但訪問速度降低了;

在c語言中,結構是一種復合資料型別,其構成元素既可以是基本資料型別(如int、long、float等)的變數,也可以是一些復合資料型別(如陣列、結構、聯合等)的資料單元。在結構中,編譯器為結構的每個成員按其自然對界(alignment)條件分配空間。各個成員按照它們被宣告的順序在記憶體中順序儲存,第乙個成員的位址和整個結構的位址相同。

例如,下面的結構各成員空間分配情況:

struct test

; 結構的第乙個成員x1,其偏移位址為0,佔據了第1個位元組。第二個成員x2為short型別,其起始位址必須2位元組對界,因此,編譯器在x2和x1之間填充了乙個空位元組。結構的第三個成員x3和第四個成員x4恰好落在其自然對界位址上,在它們前面不需要額外的填充位元組。在test結構中,成員x3要求4位元組對界,是該結構所有成員中要求的最大對界單元,因而test結構的自然對界條件為4位元組,編譯器在成員x4後面填充了3個空位元組。整個結構所佔據空間為 12位元組。

更改c編譯器的預設位元組對齊方式

在預設情況下,c編譯器為每乙個變數或是資料單元按其自然對界條件分配空間。一般地,可以通過下面的方法來改變預設的對界條件:

· 使用偽指令#pragma pack (n),c編譯器將按照n個位元組對齊。

· 使用偽指令#pragma pack (),取消自定義位元組對齊方式。

另外,還有如下的一種方式:

· __attribute((aligned (n))),讓所作用的結構成員對齊在n位元組自然邊界上。如果結構中有成員的長度大於n,則按照最大成員的長度來對齊。

· __attribute__ ((packed)),取消結構在編譯過程中的優化對齊,按照實際占用位元組數進行對齊。

以上的n = 1, 2, 4, 8, 16... 第一種方式較為常見。

intel和微軟和本公司同時出現的面試題

#pragma pack(8)

struct s1;

struct s2;

問1.sizeof(s2) = ?

2.s2的c後面空了幾個位元組接著是d?

結果如下:

sizeof(s2)結果為24.

成員對齊有乙個重要的條件,即每個成員分別對齊.即每個成員按自己的方式對齊.也就是說上面雖然指定了按8位元組對齊,但並不是所有的成員都是以8位元組對齊.其對齊的規則是,每個成員按其型別的對齊引數(通常是這個型別的大小)和指定對齊引數(這裡是8位元組)中較小的乙個對齊.並且結構的長度必須為所用過的所有對齊引數的整數倍,不夠就補空位元組.

s1中,成員a是1位元組預設按1位元組對齊,指定對齊引數為8,這兩個值中取1,a按1位元組對齊;成員b是4個位元組,預設是按4位元組對齊,這時就按4位元組對齊,所以sizeof(s1)應該為8;

s2 中,c和s1中的a一樣,按1位元組對齊,而d 是個結構,它是8個位元組,它按什麼對齊呢?對於結構來說,它的預設對齊方式就是它的所有成員使用的對齊引數中最大的乙個,s1的就是4.所以,成員d就是 按4位元組對齊.成員e是8個位元組,它是預設按8位元組對齊,和指定的一樣,所以它對到8位元組的邊界上,這時,已經使用了12個位元組了,所以又新增了4個位元組 的空,從第16個位元組開始放置成員e.這時,長度為24,已經可以被8(成員e按8位元組對齊)整除.這樣,一共使用了24個位元組.

位域之我見

有些資訊在儲存時,並不需要占用乙個完整的位元組,而只需佔幾個或乙個二進位制位。例如在存放乙個開關量時,只有0和1 兩種狀態,用一位二進位即可。為了節省儲存空間,並使處理簡便,語言提供了一種資料結構,稱為 位域 或 位段 所謂 位域 是把乙個型別單元中的二進位劃分為幾個不同的區域,並說明每個區域的位數...

C語言位域 位段

有些資訊在儲存時,並不需要占用乙個完整的位元組,而只需佔幾個或乙個二進位制位。例如開關只有通電和斷電兩種狀態,用0和1表示足以,也就是用乙個二進位。所以c語言又提供了一種資料結構,稱為位域或 位段。位域在應用開發中較少使用,你可以暫時跳過,遇到相關問題再回來溫習。所謂 位域 是把乙個位元組中的二進位...

C語言位域 位段

有些資訊在儲存時,並不需要占用乙個完整的位元組,而只需佔幾個或乙個二進位制位。例如開關只有通電和斷電兩種狀態,用0和1表示足以,也就是用乙個二進位。所以c語言又提供了一種資料結構,稱為位域或位段。位域在應用開發中較少使用,你可以暫時跳過,遇到相關問題再回來溫習。所謂 位域 是把乙個位元組中的二進位劃...