C語言中的int類型的範圍是由什麼決定的

C語言中的int類型的範圍是由什麼決定的

在 K&R 經典教材 The C Programming Language 的2.2節中,對 int 類型是這樣描述的

an integer, typically reflecting the natural size of integers on the host machine

意思是反映了機器整數類型的 natural size,可是,

這個 natural size 又是什麼意思呢?

書中後來在談到 short, int, long 的關係時,又說,這些類型由編譯器根據機器自由選擇合適的大小,但是 short 和 int 至少 16 位,long 至少 32 位。

這裏的問題是

編譯器是根據什麼決定類型大小呢?

後面書中又提到,這些類型啊,在<limits.h>中都有,我就在ubuntu下查看了 /usr/include/limits.h,裏面確實提到

/* Minimum and maximum values a `signed int' can hold.  */
#  define INT_MIN   (-INT_MAX - 1)
#  define INT_MAX   2147483647

但是,這也是一種定義,還是沒有說出爲什麼,我現在想知道的是

爲什麼

於是,我想起了那些年掃過的 《深入理解計算機系統》,英文名叫 Computer Systems: A Programmer's Perspective,速查之!

在2.1節的開頭提到,字節(byte)是最小可尋址單位,大多數計算機使用8位的塊。 啊,8位,那位又是什麼呢?嗯,位是一種存儲結構,一個位只能存儲0或者1。

後面2.1.2節中提到

每臺計算機都有一個字長(word size),指明瞭整數和指針數據的 nominal size。

指針是什麼,指針就是內存中的地址啊,假如字長爲w位,那麼地址的數目就是2^w個啊,那一個地址代表多大內存呢?

前面說了,字節(byte)是最小可尋址單位,所以一個地址代表一個字節。當字長是w位時,地址數目2^w個,共有2^w個字節的內存空間。

如果計算機字長爲32,即傳說中的32位計算機,那麼它可以表示的內存空間就是 2^32 個字節,這就是傳說中的4G啊!

現在我們是由字長32位,也就是整數的大小32位,推出了內存空間4G。我現在在想:

是不是一開始是決定內存空間是4G,所以才定下了字長32位的規矩,由此,機器的natural size是32位, 所以,編譯器纔將C語言中int類型纔是32位呢?

可是我沒有證據啊!

沒有證據就嘗試推理一下吧。

我們知道32位機器是由16位機器擴展來的,那爲什麼要擴展機器字長呢?這個問題原因之一,我們剛纔已經解釋過了,如果不擴展,那麼機器最大尋址空間就比較小,即使我給你一個大內存,你也用不上啊。這可能這也今天我們從32位轉到64位的原因吧。

所以,現在我們明白了,由於我們想要更大的內存地址空間,所以就將字長從16位提升爲32位,而字長代表着指針和整數類型的大小,所以最終整數類型就是32位了。

不過這裏還有不少問題。

字長這東西只是個抽象的概念,方便我們描述機器的一些屬性,暫時不談。

先說指針。對於機器來說,哪裏有什麼指針的概念,指針是C語言中的東西,編譯成彙編後就沒指針這個概念了。但是,指針表示的是內存的地址,而內存的地址又和機器中的什麼部件相關呢?

再說整數。到彙編這一層,整數的概念還存在嗎?整數的概念應該是和彙編中的算術指令相關,那麼算術指令又和機器中的什麼部件相關呢?

最後,指針是表示內存地址啊,我們有了更大內存,那麼內存地址需要更長的位來表示是可以理解的,可是,這關你整數什麼事啊?我內存地址32位,整數16位不行嗎?

其實,總的問題就是

字長都與機器的什麼部件相關

要解釋這個問題,我們發現自己不由自主地來到了《深入理解計算機系統》的第四章“處理器體系結構”。

這一章以一種叫Y86的處理器介紹了處理器體系結構的方方面面。首先介紹了寄存器,寄存器是一種存儲部件,存儲什麼?存儲信息,存儲信息用來做什麼呢?用來計算。我們在C語言中使用一個簡單的加法計算,在處理器這一層,就需要使用寄存器來幫助我們計算。我們把一個簡單的C語言編譯成彙編看看。

/* test_add.c */
#include <stdio.h>

int main(void) {
    int a = 1;
    int b = 2;
    int c = a + b;

    return 0;
}

使用 GCC 編譯一下

   gcc -S test_add.c -o test_add.s

然後查看一下主要代碼。

    movl    $1, -12(%ebp)
    movl    $2, -8(%ebp)

    movl    -8(%ebp), %eax
    movl    -12(%ebp), %edx

    addl    %edx, %eax
    movl    %eax, -4(%ebp)

其中的 ebp eax edx 就是寄存器。

可以看出,數據先放到棧裏,再從棧裏放到寄存器裏,然後再進行加法運算,最後再從寄存器裏把結果放回棧裏。

下面的圖是書中給出的一個處理器的抽象視圖:


棧是什麼?棧是一種抽象概念,這裏的棧就是指內存。

書裏說了,在32位計算機中,這些寄存器的大小就是32位。可見,

字長與寄存器大小一樣

除此之外,我們可以看到,需要計算的時候,movl 指令將數據從內存中放到寄存器裏,由於內存和寄存器是不同的部件,所以需要一個部件來傳遞數據,這種部件叫做數據總線。

寄存器的大小與字長相同,那麼這種數據總線每次能傳送的數據也應該與字長相同,所以:

字長與數據總線寬度一樣

另外,再想像一下,你想要從內存中取數據出來,總要告訴內存你取的是哪個地址的數據吧,所以,“地址”這個數據也是要從某個地方傳送到內存的。只要傳遞,就需要有部件支持,這個部件叫做地址總線,地址總線傳遞地址,地址大小與字長一樣,那麼,我們可以知道:

字長與地址總線寬度一樣

好了,到了這裏,我們的分析就差不多了,總結一下:

我們由C語言中int類型的大小,得到了字長這個概念,又從字長這個概念尋找了與其相關的一些機器部件的屬性。到現在爲此,與字長相關的有:

  • int 類型
  • 指針(即內存地址)
  • 寄存器
  • 數據總線
  • 地址總線

在 Wikipedia 的 Word(computer_architecture)詞條中,我們可以看到自1837年以來,一系列計算機體系結構中與字長相關的一些屬性的變化。

我們再想想,爲什麼要將這麼多種部件都設置成相同長度?我想,可能是因爲計算機內部實在太複雜了,各個部件之間需要緊密地配合,共同完成複雜的任務。尤其是數據,需要在各個部件之間傳遞,如果這些部件之間大小不統一,就會增加機器的複雜度,由於,我們將這些部件大小儘可能統一,進而提出字長這種概念來描述計算機的重要性質。

到這裏,我們再想一下,字長這個概念和這麼多部件相關,那麼確定字長多大應該不僅僅與內存大小有關係。比如字長代表寄存器的大小,寄存器與機器的運算直接相關,字長變大後,每次能參與計算的值也相應變大,以前我們計算兩個很大的數的和時,可能需要動用好幾個寄存器,現在咱字長大了,寄存器也大了,只需要兩個寄存器就可以了。

由此可見,字長的確定是一個綜合的考量,代表着計算機計算,存儲能力的全面提升。

文章結束了,思考永不停止。


轉載自 http://blog.csdn.net/on_1y/article/details/20660155

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