1. 程式人生 > >Linux 中結構體的記憶體分配問題

Linux 中結構體的記憶體分配問題


不要用sizeof(struct gg),這個不能說明問題,你需要在定義一個gg的變數後,再在其後定義另一個變數,將這兩個變數的地址相減才能求出實際結果,而且你的測試一定是在VC中,GCC中是4個位元組的

不能用這種方式來求結構體佔用的空間,這是不準確的,不過在另一種程度上可以說得過去,因為結構體地址是被4整除,而結構體的第一個成員所在地址與結構體本身所佔地址之間沒有空洞存在的,而其成員又只佔一個位元組,所以VC編譯器的sizeof語句就把它設成了一個位元組,這跟編譯器密切相關,你換成GCC之後就不一樣了,無論這個表達示的結果如何,其記憶體佔用空間的佈局是可以預測的,只要知道了這個道理,就可以舉一反三了,所以那些面試題出的sizeof之類的簡直沒有任何意義,不去追求本質,去追求現象有什麼用呢???
之所以在VC下的sizeof設成這種規則,其目的是讓人更好理解,遮蔽了細節,讓人知其然不知其所以然,細想一下:什麼時候會用sizeof,無非就是填充資料的時候,如果你需要動態地確定該填多少位元組,比較好的方法就是先用sizeof這個表達示求出來,在
struct gg
{
char a;
}
中,寫程式碼的人一看就知道只有一個位元組被佔用,所以理所當然就只填充一個位元組進去,餘下的工作就交給編譯器去做,因為編譯器會自動填充餘下的三個空洞,而但是sizeof(struct gg)=1讓人看起來更自然,因為其內容就只有一個位元組啊,當然結果就應該是1個位元組了啊,無論你將sizeof表達示的值置成1或者4,對程式結果沒有任何影響,用下面的例子來說明:
struct gg test;
memset(&test,0,sizeof(struct gg));
如果sizeof(struct gg)結果是1,那麼記憶體中接下來的三個位元組就是編譯器填充的固定字元,這個字元在GCC下就是0xc, 也就是說記憶體中第一個位元組是0,接下來的三個位元組是0xc,如果sizeof(struct gg)結果是4,那麼記憶體中的四個位元組都是0,說到這裡,好像結果造成了明顯的不同之處,但實際沒有什麼影響,接下來,如果呼叫下面一條語句:
test.a='a';
那麼編譯器會幫你做一個工作,你將其反彙編看一下就明白了,就是將四個位元組全部取出,但會忽略掉三個位元組,也就是讓那三個位元組形同虛設,而只取那個a所佔8位的資料,並修改其資料,其餘24位不變,最後再存回記憶體,所以無論你的sizeof(struct gg)是1或是4,對你的程式碼是透明的!!!!!而微軟的東東一向就是以易用為原則,為了讓程式設計師更好理解,所以就讓sizeof(struct gg)等於1,而不是4,隨之而來的就會給想要了解其細節的人設了一道障礙,而GCC剛好相反,處處在顯示其實現細節,而不是隱藏細節

最後還想多說兩句:現在很多公司的面試題都考這個內容,其實這些人出題根本不嚴謹,沒有說是什麼CPU,什麼平臺,什麼編譯器,不同的環境下其結果是不同的,而且根本就沒考出重點,重點是在理解記憶體佈局,是在編譯器的處理,而不是一個表達示,這個表達示,死背都背得出來,但很少人能說出為什麼!!!!!
你可以寫下下面的測試程式碼,觀測其執行結果,再回頭來思考:
#include <stdio.h>
struct gg
{
char a;
}

stuct gg test;
char test_str_temp1[4];
char test_str_temp2[4];

int main(int argc,char **argv)
{
memcpy(test_str_temp1,&test,4);
test.a = 'a';
memcpy(test_str_temp2,&test,4);
printf("*******0x%x 0x%x 0x%x 0x%x *******/n",test_str_temp1[0],test_str_temp1[1],test_str_temp1[2],test_str_temp1[3]);
printf("*******0x%x 0x%x 0x%x 0x%x *******/n",test_str_temp2[0],test_str_temp2[1],test_str_temp2[2],test_str_temp2[3]);
printf("------0x%x---------/n",test.a);
return 0;
}