天天看點

vc 淺談sizeof

此為“小紫”對sizeof的一些見解,是以發出來給大家分享下,發現網上對記憶體對齊的說法不統一,

是以才實驗了一下,得出來了一個“标準”。(我知道網上有很多比我這篇文章更具體,更詳細,但我會

努力把這篇文章寫得通俗易懂,讓大家更容易了解。另外,第五部分是我寫這篇文章的原因)

    如果您有轉載的欲望,請您能夠保留這版權資訊。這是讀者們唯一可以信任的東西。(本篇文章在

WIN32平台下寫,是以位元組大小也以WIN32為标準)

本文首發至本人部落格中.

   一、為什麼要讀這篇文章?

       這篇文章面對初學者設計,通過這篇文章來了解記憶體中類型或變量所占位元組的“藝術”,如果覺

得本文太簡單,我可以推薦一篇文章:《詳細解析C語言中的sizeof》,本文有很多細節也是參考的那裡

。如果前幾個部分太簡單,可以從第五部分看起。

   二、什麼是sizeof?

        sizeof其實是一個操作符,而并非是一個函數,寫成“括号形式”(我把加“()”的任何語句

形式都叫“括号形式”)隻是它的一種普遍寫法。sizeof可以得到操作符所占用記憶體位元組數的大小。

sizeof操作符可以為變量、基本類型(int,float等都是基本類型)、結構體。

   三、sizeof的格式

       (1)對于變量有兩種格式:

           ①sizeof(變量);

           ②sizeof 變量;這種格式是允許的。但是不普遍。

       (2)對于結構體和基本類型隻有一種寫法:

          sizeof(結構名字、基本類型名);

   四、注意!

       不确定所占記憶體大小的類型(包括不确定大小的共用結構(聯合結構)等),void類型和函數等不可

以作為sizeof的操作符。sizeof的傳回值為size_t(也就是unsigned int)。指針的大小根據編譯器決定。

   五、sizeof的結果

       在開始正文之前,請大家看一個程式 段:

       long double p[2]={0.0};

       int abc(long double a[])

       {

         unsigned int fR=sizeof(a);

         return fR;

       }

       那麼現在該告訴我,函數的傳回值是多少?

        嗯,也許你會回答(隻是也許,我知道,這個世界上不乏有高手的存在),傳回值是12(一個

long double所占記憶體的位元組為12),但是函數卻傳回了4。其實,這是編譯器的一次“小惡作劇”,我們

都知道,編譯器有兩大任務:1.編譯成可執行檔案。2.優化代碼。但是編譯器為了簡化編譯,讓數組在傳

入函數的時候産生了意外,被當作了指針處理,以此來簡化編譯。是以結果傳回的是sizeof(long

double*).嗯~~如果你不相信的話,我可以給你一個完整的程式 段去實驗一下:

           #include <stdio.h>

           int abc(long double a[])

           {

              unsigned int fR=sizeof(a);

              return fR;

           }

           int main(void)

           {

             long double p[2]={0.0};

             printf("%d",abc(p));

             return 0;

           }

       各位也許認為上面那道題目太簡單了。那麼我們這次就可以來一個…………………………………

…更簡單的了。

       struct M

       {

         char a;

         int b;

         long c;

       }

       如果我們現在來sizeof(M)那麼得到的結果是什麼呢?也許你這次會說是9,或15。(隻是也許。

我知道,高手有很多。)但是正确的答案是16。下面我将為讀者來解釋下這個答案的名字:這是C99的一

個标準,它的名字叫記憶體對齊。CPU在通路記憶體對齊的變量的時候,速度會加快。可以說,這是标準跟我

們開的一個玩笑。

       當然,為了以後我們能夠準确計算出結構體所占的空間,我将為電腦 前的您來講解如何計算這種

“特殊的結果”。

       您有兩種方法來了解“記憶體對齊”,但在文章的最後,我将會講解這兩種方法之間的微妙關系。

        1.在大多數編譯器中,預設的記憶體對齊大小為8。當資料的大小大于8時,也會被當做8處理。當

然,你也可以更改。我們來依次了解:

         //我們先要知道,我們可以以8個位元組為一個大機關,當然,這個8是可以更改的。

         char a; //那麼char的位元組為1,先進入到了這個“大機關”中

         int b;//int為4位元組,大機關中還餘下了7個小機關,也可以擠進去。

         long c;//long也為4位元組,可是此時大機關中還隻剩下了3個機關,因為有5個機關被char和int

使用了。是以不能再擠進去了,于是另外開辟了一個大機關,把4個小機關放了進入。至此,總共用了2個

大機關,而一個大機關是8個小機關,也就是8個位元組,是以最終的結果是8*2=16位元組。

        2.嗯,我們還有另一種方法來了解,這種了解起來要難得多。

          我們可以把結構體内的成員當作一個個的乘客,人人都想到第一個位置,也就是在記憶體中的首

位置。但是這個位置隻有第一個成員才可以拿到。我們可以把他所在的位置與頭位置的差叫做“偏移量”

。當偏移量是本身所占位元組的倍數的時候,就不用填補。而不是的時候,就要填補到是自身的倍數,并且

自身要占8個位元組。

         char a;//此時偏移量為0,是1的倍數。此時所占大小為1

         int b;//此時偏移量為1,因為前面的char所占了一個位元組。1不是4的倍數,是以要加3,以變

成4,成為4的倍數,并且b本身也占了8個位元組(可以當成運氣不好的懲罰吧,呵呵),那麼此時又占了

3+8個位元組。總占11個位元組。

         long c;//此時偏移量為1+11=12。12是4的倍數,是以無需另加機關。此時又占了4個位元組。總

占4+11+1個位元組,也就是16個位元組。

         說了這麼多。其實兩種方法也就是一個方法。當判斷偏移量是否為自身大小的倍數的時候,其

實就是在判斷“是否還能夠擠進一個大機關”中。當全部判斷完後。空的大小(也就是對齊的大小)是一

樣的。

摘自:http://www.hack4.com/article/hack4-21692.html