變數的宣告,會配置其所需的記憶體。每種變數所需的大小不一樣,比如說char是1 bytes,int 是4 bytes,double則是8 bytes。如果是這樣,那這些大小在記憶體中是如何擺放呢?是直覺的一個接一個放嗎?其實不然。這牽扯到performance / efficiency的問題! 在32 bits的架構上,一次的資料存取也就是32 bits (4 bytes)。而這4 bytes 不是隨便從哪個點抓都可以,而是以4 bytes為單位,不管需要的是其中那個byte,就抓那4個bytes。比如說,抓第0,4,8 ,12....等,而不會是從3,7,9開始抓4個bytes。
這代表什麼呢?這表示了對齊 (alignment)的重要,因為會影響到幾次才抓的完。如果要抓一個4 bytes 的int,而這個int是從6擺到10,那就表示要抓兩次,自然效能較差了。因此,在struct的宣告是存在對齊這件事的。見下例:
#include <stdio.h>
int main(int argc, char* argv[])
{
struct align_test
{
char x; //1 byte
int y; //4 bytes
short int z; //2bytes
};
struct align_test test;
printf("test size is %d\n", sizeof(test));
printf("x size is %d\n", sizeof(test.x));
printf("y size is %d\n", sizeof(test.y));
printf("z size is %d\n", sizeof(test.z));
printf("address of test is %p\n", &test);
printf("address of x is %p\n", &test.x);
printf("address of y is %p\n", &test.y);
printf("address of z is %p\n", &test.z);
return 0;
}
align_test有3個成員,這樣算一算,一個align_test的structure應該是佔1+4+2=7個bytes,但結果如下:
test size is 12
x size is 1
y size is 4
z size is 2
address of test is 0xbfd450a8
address of x is 0xbfd450a8
address of y is 0xbfd450ac
address of z is 0xbfd450b0
注意看其位址
|----|----|----|----|----|----|----|----|----|----|----|----|
8 9 c 0 4
x p p p y y y y z z p p
以4 bytes alignment來說x用了8,y要4 bytes,只好從c開始放,因為9,10,11放不下。然後z 2 byte,放在0,1。沒用到的,就是所謂的padding了,因此如果是這樣宣告,其實是變成下面這樣
struct align_test
{
char x; //1 byte
char padding0[3];
int y; //4 bytes
short int z; //2bytes
char padding1[2];
};
這樣的存取效率會比較好。但有沒有辦法做改變?比如說大家擠一下,不要浪費空間。當然是有的,可以這樣做
#pragma pack(push) /* push current alignment to stack */
#pragma pack(16) /* set alignment to 1 16 byte boundary */
struct align_test
{
char x; //1 byte
int y; //4 bytes
short int z; //2bytes
};
#pragma pack(pop) /* restore original alignment from stack */
結果如下,從其address也看的出來:
test size is 7
x size is 1
y size is 4
z size is 2
address of test is 0xbfa06d6d
address of x is 0xbfa06d6d
address of y is 0xbfa06d6e
address of z is 0xbfa06d72
progma是設定其做幾個byte的對齊,但只能往下設定,以該結構中成員size最大的為上限。比如說,int是4byte,只能改成1,2,或4。因此,改成8,16都會被忽略,而用4來配置。通常會發生在控制硬體時改變其pragma,以便根據其大小來正確的取址,而不用煩惱padding。
當然,也可以硬幹,把程式寫的聰明一點,擺放整齊。比如說,換個位置:
struct align_test
{
char x; //1 byte
short int y; //2bytes
int z; //4 bytes
};
結果如下:
test size is 8
x size is 1
y size is 2
z size is 4
address of test is 0xbfa565bc
address of x is 0xbfa565bc
address of y is 0xbfa565be
address of z is 0xbfa565c0
Reference
留言列表