sizeof小覽



一、文章來由—一道面試題遷出的探究

我發現我已經形成一種習慣寫來由了,以後看博客的時候可以讓我回憶起爲什麼出現這個問題,我用什麼方法解決的,既然形成習慣就讓這個習慣保持下去吧。今天實驗室師姐在看書,一處不解,是關於sizeof的,大家討論此問題後,我一向信服做了才知道答案,於是有了這篇文章。但是隻能叫小覽,因爲不可能總結完sizeof的用法,歡迎補充和討論。

二、從這道題目說起

我直接將問題的關鍵部分提出來:

<code class="language-c++ hljs cpp has-numbering"><span class="hljs-built_in">string</span> strArr1[] = { <span class="hljs-string">"Trend"</span>, <span class="hljs-string">"Micro"</span>, <span class="hljs-string">"Soft"</span> };
<span class="hljs-built_in">cout</span> << <span class="hljs-string">"sizeof(strArr1) == "</span> << <span class="hljs-keyword">sizeof</span>(strArr1) << endl;</code><ul class="pre-numbering" style="display: block;"><li>1</li><li>2</li></ul>

請問輸出多少,書上的答案這樣寫道:

而字符串strArr1是由3段構成的,所 以sizeof(strArr1)大小是12。
首先要明確sizeof不是函數,也不是一元運算符,它是個類似宏定義的特殊關鍵字,特別是sizeof(string)=4

這個不去試是不知道的,因爲編譯器那麼多,編譯器做什麼事情不去試怎麼可能知道

果然,在vs2013 release模式下結果是

sizeof(string) == 24
sizeof(strArr1) == 72

debug模式

sizeof(string) == 28
sizeof(strArr1) == 84

也是3倍關係,因爲這是一個string數組,裏面有三個string對象

那麼爲什麼string有不同的結果?

查閱了相關資料得出結論:我們知道char*肯定是4字節,string裏面可能不止包含一個char*那麼簡單,還包含有長度信息等其他信息,string的實現在各庫中可能有所不同,但是在同一庫中相同一點是,無論你的string裏放多長的字符串,它的sizeof()都是固定的,字符串所佔的空間是從堆中動態分配的,與sizeof()無關。

  sizeof(string)=4可能是最典型的實現之一,不過也有sizeof()爲12、32字節的庫實現。 但是VC6.0測試後sizeof(string)=16.還是跟編譯器有關

爲了完全測試一些東西,我測試越寫越多,然後我來了威力加強版,見代碼:

<code class="language-c++ hljs cpp has-numbering"><span class="hljs-preprocessor">#include<iostream></span>

<span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> <span class="hljs-built_in">std</span>;

<span class="hljs-keyword">int</span> main()
{
    <span class="hljs-keyword">char</span> p[] = { <span class="hljs-string">'a'</span>, <span class="hljs-string">'b'</span>, <span class="hljs-string">'c'</span>, <span class="hljs-string">'a'</span>, <span class="hljs-string">'b'</span>, <span class="hljs-string">'c'</span> };
    <span class="hljs-keyword">char</span> *p1 = <span class="hljs-string">"abcabc"</span>;
    <span class="hljs-keyword">char</span> p2[] = <span class="hljs-string">"abcabc"</span>;
    <span class="hljs-keyword">char</span> p3[][<span class="hljs-number">2</span>] = { { <span class="hljs-string">'a'</span>, <span class="hljs-string">'b'</span> }, { <span class="hljs-string">'c'</span>, <span class="hljs-string">'a'</span> }, { <span class="hljs-string">'b'</span>, <span class="hljs-string">'c'</span> } };
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"p == %s\n"</span>, p);
    <span class="hljs-built_in">cout</span> << p << endl;
    <span class="hljs-built_in">cout</span> << <span class="hljs-string">"sizeof(p) == "</span> << <span class="hljs-keyword">sizeof</span>(p) << endl;
    <span class="hljs-built_in">cout</span> << <span class="hljs-string">"sizeof(p1) == "</span> << <span class="hljs-keyword">sizeof</span>(p1) << endl;
    <span class="hljs-built_in">cout</span> << <span class="hljs-string">"sizeof(p2) == "</span> << <span class="hljs-keyword">sizeof</span>(p2) << endl;
    <span class="hljs-built_in">cout</span> << <span class="hljs-string">"sizeof(p3) == "</span> << <span class="hljs-keyword">sizeof</span>(p3) << endl;

    <span class="hljs-built_in">cout</span><<<span class="hljs-string">"sizeof(string) == "</span> << <span class="hljs-keyword">sizeof</span>(<span class="hljs-built_in">string</span>) << endl;

    <span class="hljs-built_in">string</span> strArr1[] = { <span class="hljs-string">"Trend"</span>, <span class="hljs-string">"Micro"</span>, <span class="hljs-string">"Soft"</span> };
    <span class="hljs-built_in">cout</span> << <span class="hljs-string">"sizeof(strArr1) == "</span> << <span class="hljs-keyword">sizeof</span>(strArr1) << endl;

    <span class="hljs-keyword">int</span> a = <span class="hljs-number">0</span>;
    <span class="hljs-built_in">cout</span> <<<span class="hljs-string">"sizeof(a = 3) == "</span> << <span class="hljs-keyword">sizeof</span>(a = <span class="hljs-number">3</span>) << endl;
    <span class="hljs-built_in">cout</span> << <span class="hljs-string">"a == "</span> << a << endl;

    <span class="hljs-built_in">cout</span> << <span class="hljs-string">"sizeof(999999) == "</span> << <span class="hljs-keyword">sizeof</span>(<span class="hljs-number">999999</span>) << endl;
    <span class="hljs-built_in">cout</span> << <span class="hljs-string">"sizeof(9999999999999999999) == "</span> << <span class="hljs-keyword">sizeof</span>(<span class="hljs-number">9999999999999999999</span>) << endl;
    <span class="hljs-built_in">cout</span> << <span class="hljs-string">"sizeof(9 / 5) == "</span> << <span class="hljs-keyword">sizeof</span>(<span class="hljs-number">9</span> / <span class="hljs-number">5</span>) << endl;
    <span class="hljs-built_in">cout</span> << <span class="hljs-string">"sizeof((double)9 / 5) == "</span> << <span class="hljs-keyword">sizeof</span>((<span class="hljs-keyword">double</span>)<span class="hljs-number">9</span> / <span class="hljs-number">5</span>) << endl;

    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}</code><ul class="pre-numbering" style="display: block;"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li></ul>

運行結果如圖所示:
這裏寫圖片描述

我來一一解釋我的這些測試在做什麼:
(1)首先p的這種初始化方式,在末尾不會加’\0’,所以 sizeof(p) == 6;而且一個有趣的問題是printf和cout直接輸出p是不同的,printf是要碰到’\0’結束,我也看了printf和cout的彙編代碼,但是沒有細究,之後又空詳細研究一下
(2)p1和p2的sizeof不同,因爲一個是指針,一個是字符數組,指針在Win32編譯環境下的sizeof都是4,因爲是4字節的地址,32bits可尋址空間
(3)p3是另一個有趣的問題,p3不能寫成p3[3][]來初始化,因爲這樣初始化要保證二維數組每一行的個數相同,也就是不能出現“參差不齊”的情況,那種情況要動態分配
(4)這是一個陷阱

<code class="language-c++ hljs cpp has-numbering"><span class="hljs-keyword">int</span> a = <span class="hljs-number">0</span>;
<span class="hljs-built_in">cout</span><<<span class="hljs-keyword">sizeof</span>(a=<span class="hljs-number">3</span>)<<endl;
<span class="hljs-built_in">cout</span><<a<<endl;</code><ul class="pre-numbering" style="display: block;"><li>1</li><li>2</li><li>3</li></ul>

輸出爲什麼是4,0 而不是期望中的4,3???就在於sizeof在編譯階段處理的特性。由於sizeof不能被編譯成機器碼,所以sizeof作用範圍內,也就是()裏面的內容不能被編譯,而是被替換成類型。=操作符返回左操作數的類型,所以a=3相當於int,而代碼也被替換爲:

<code class="language-c++ hljs cpp has-numbering"><span class="hljs-built_in">cout</span><<<span class="hljs-number">4</span><<endl;
<span class="hljs-built_in">cout</span><<a<<endl;</code><ul class="pre-numbering" style="display: block;"><li>1</li><li>2</li></ul>

所以,sizeof是不可能支持鏈式表達式的,這也是和一元操作符不一樣的地方。

不要把sizeof當成函數,也不要看作一元操作符,把他當成一個特殊的編譯預處理。

(5)這樣的原因是999999是一個編譯器int型可以搞定的數,所以按int來處理,太大的數不能用int搞定,但是8個字節一定可以搞定的

sizeof(999999) == 4
sizeof(9999999999999999999) == 8

(6)最後是看了(9 / 5)編譯器是作爲int看待的,強制轉換後纔是double

三、sizeof 能總結多少是多少

sizeof博大精深,即使看了很多資料,一口氣總結完也是不可能了,總結常用的就好。

1、什麼是sizeof

首先看一下sizeof在msdn上的定義:

The sizeof keyword gives the amount of storage, in bytes, associated with a variable or a type (including aggregate types). This keyword returns a value of type size_t.

看到return這個字眼,是不是想到了函數?錯了,sizeof不是一個函數,你見過給一個函數傳參數,而不加括號的嗎?sizeof可以,所以sizeof不是函數。網上有人說sizeof是一元操作符,但是我並不這麼認爲,因爲sizeof更像一個特殊的宏,它是在編譯階段求值的。舉個例子:
<code class="language-c++ hljs cpp has-numbering"><span class="hljs-built_in">cout</span><<<span class="hljs-keyword">sizeof</span>(<span class="hljs-keyword">int</span>)<<endl; <span class="hljs-comment">// 32位機上int長度爲4</span>
<span class="hljs-built_in">cout</span><<<span class="hljs-keyword">sizeof</span>(<span class="hljs-number">1</span>==<span class="hljs-number">2</span>)<<endl; <span class="hljs-comment">// == 操作符返回bool類型,相當於 cout<<sizeof(bool)<<endl;</span></code><ul class="pre-numbering" style="display: block;"><li>1</li><li>2</li></ul>
在編譯階段已經被翻譯爲:
<code class="language-c++ hljs cpp has-numbering"><span class="hljs-built_in">cout</span><<<span class="hljs-number">4</span><<endl;
<span class="hljs-built_in">cout</span><<<span class="hljs-number">1</span><<endl;</code><ul class="pre-numbering" style="display: block;"><li>1</li><li>2</li></ul>

2、語法

sizeof有三種語法形式,如下:

1) sizeof( object ); // sizeof( 對象 );
2) sizeof( type_name ); // sizeof( 類型 );
3) sizeof object; // sizeof 對象;
所以,

int i;
sizeof( i ); // ok
sizeof i; // ok
sizeof( int ); // ok
sizeof int; // error
既然寫法1可以完全代替寫法3,爲求形式統一以及減少我們大腦的負擔,第3種寫法,忘掉它吧!

實際上,sizeof計算對象的大小也是轉換成對對象類型的計算,也就是說,同種類型的不同對象其sizeof值都是一致的。這裏,對象可以進一步延伸至表達式,即sizeof可以對一個表達式求值,編譯器根據表達式的最終結果類型來確定大小,一般不會對表達式進行計算。如:

sizeof( 2 ); // 2的類型爲int,所以等價於 sizeof( int );
sizeof( 2 + 3.14 ); // 3.14的類型爲double,2也會被提升成double類型,所以等價於 sizeof( double );

3、函數的sizeof

函數類型

考慮下面的問題:
<code class="language-c++ hljs cpp has-numbering"><span class="hljs-keyword">int</span> f1(){<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;};
<span class="hljs-keyword">double</span> f2(){<span class="hljs-keyword">return</span> <span class="hljs-number">0.0</span>;}
<span class="hljs-keyword">void</span> f3(){}

<span class="hljs-built_in">cout</span><<<span class="hljs-keyword">sizeof</span>(f1())<<endl; <span class="hljs-comment">// f1()返回值爲int,因此被認爲是int</span>
<span class="hljs-built_in">cout</span><<<span class="hljs-keyword">sizeof</span>(f2())<<endl; <span class="hljs-comment">// f2()返回值爲double,因此被認爲是double</span>
<span class="hljs-built_in">cout</span><<<span class="hljs-keyword">sizeof</span>(f3())<<endl; <span class="hljs-comment">// 錯誤!無法對void類型使用sizeof</span>
<span class="hljs-built_in">cout</span><<<span class="hljs-keyword">sizeof</span>(f1)<<endl;   <span class="hljs-comment">// 錯誤!無法對函數指針使用sizeof   </span>
<span class="hljs-built_in">cout</span><<<span class="hljs-keyword">sizeof</span>*f2<<endl;   <span class="hljs-comment">// *f2,和f2()等價,因爲可以看作object,所以括號不是必要的。被認爲是double</span></code><ul class="pre-numbering" style="display: block;"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li></ul>

結論:對函數使用sizeof,在編譯階段會被函數返回值的類型取代

4、數組的sizeof

<code class="language-c++ hljs cpp has-numbering"><span class="hljs-keyword">char</span> a[] = <span class="hljs-string">"abcdef"</span>;
<span class="hljs-keyword">int</span> b[<span class="hljs-number">20</span>] = {<span class="hljs-number">3</span>, <span class="hljs-number">4</span>};
<span class="hljs-keyword">char</span> c[<span class="hljs-number">2</span>][<span class="hljs-number">3</span>] = {<span class="hljs-string">"aa"</span>, <span class="hljs-string">"bb"</span>};

<span class="hljs-built_in">cout</span><<<span class="hljs-keyword">sizeof</span>(a)<<endl; <span class="hljs-comment">// 7</span>
<span class="hljs-built_in">cout</span><<<span class="hljs-keyword">sizeof</span>(b)<<endl; <span class="hljs-comment">// 20*4=80</span>
<span class="hljs-built_in">cout</span><<<span class="hljs-keyword">sizeof</span>(c)<<endl; <span class="hljs-comment">// 6</span></code><ul class="pre-numbering" style="display: block;"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li></ul>

數組a的大小在定義時未指定,編譯時給它分配的空間是按照初始化的值確定的,也就是7。c是多維數組,佔用的空間大小是各維數的乘積,也就是6。可以看出,數組的大小就是他在編譯時被分配的空間,也就是各維數的乘積*數組元素的大小。

結論:數組的大小是各維數的乘積*數組元素的大小。

這裏有一個陷阱:

<code class="language-c++ hljs cpp has-numbering"><span class="hljs-keyword">int</span> *d = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[<span class="hljs-number">10</span>];

<span class="hljs-built_in">cout</span><<<span class="hljs-keyword">sizeof</span>(d)<<endl; <span class="hljs-comment">// 4</span></code><ul class="pre-numbering" style="display: block;"><li>1</li><li>2</li><li>3</li></ul>

d是我們常說的動態數組,但是他實質上還是一個指針,所以sizeof(d)的值是4。
再考慮下面的問題:

<code class="language-c++ hljs cpp has-numbering"><span class="hljs-keyword">double</span>* (*a)[<span class="hljs-number">3</span>][<span class="hljs-number">6</span>];
<span class="hljs-built_in">cout</span><<<span class="hljs-keyword">sizeof</span>(a)<<endl;   <span class="hljs-comment">// 4</span>
<span class="hljs-built_in">cout</span><<<span class="hljs-keyword">sizeof</span>(*a)<<endl;   <span class="hljs-comment">// 72</span>
<span class="hljs-built_in">cout</span><<<span class="hljs-keyword">sizeof</span>(**a)<<endl; <span class="hljs-comment">// 24</span>
<span class="hljs-built_in">cout</span><<<span class="hljs-keyword">sizeof</span>(***a)<<endl; <span class="hljs-comment">// 4</span>
<span class="hljs-built_in">cout</span><<<span class="hljs-keyword">sizeof</span>(****a)<<endl; <span class="hljs-comment">// 8</span></code><ul class="pre-numbering" style="display: block;"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li></ul>

a是一個很奇怪的定義,他表示一個指向 double*[3][6]類型數組的指針。既然是指針,所以sizeof(a)就是4。

既然a是執行double*[3][6]類型的指針,*a就表示一個double*[3][6]的多維數組類型,因此sizeof(*a)=3*6*sizeof(double*)=72。同樣的,**a表示一個double*[6]類型的數組,所以sizeof(**a)=6*sizeof(double*)=24。***a就表示其中的一個元素,也就是double*了,所以sizeof(***a)=4。至於****a,就是一個double了,所以sizeof(****a)=sizeof(double)=8。

差不多也要結束了,如果更進一步瞭解,需要查閱更多的資料~~~

—END—


參考文獻

[1] http://blog.csdn.net/freefalcon/article/details/54839
[2] http://www.cnblogs.com/wanghetao/archive/2012/04/04/2431760.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章