深入理解計算機作業系統(三)

2021-09-01 11:26:39 字數 2263 閱讀 2156

基本資料型別

大小端模式

整型數範圍與c標準

複合型型別轉換——從short到unsigned

讓我們複習一下c語言中基本資料型別的位元組數

名稱32位

64位char11

short int22

int4

4long int48

long long int88

char *48

float44

double88

這其實是很基礎的知識,但是值得一提的是,表中只有兩個資料型別在32位和64位計算機中使用了不同的位元組數,乙個是long int,另乙個是char *。其實不只是char *,任何資料型別的指標使用的位元組數都和char *是一樣的,所以這裡更好的寫法應該是type *

為了盡量使程式可移植,要小心從32位到64位的變化。例如,在32位機器中使用int儲存變數的位址可行,但同樣的程式移植到64位機器中就成了bug。所以不如嘗試用long int儲存變數的位址。這個時候,上面的**就體現出了它的價值。

對於多於乙個位元組的資料型別,在記憶體中有兩種儲存方式,以整形數0x01234567為例

大小端模式

int value = 0x01234567;

char *ch = (char *)(&value);

if (*ch == 0x01)

else if (*ch == 0x67)

else

由於ch一定指向value最低位址的位元組,因此可以通過ch來判斷系統的大小端型別。

本文最開始就給出了各個基本資料型別的位元組數,根據位元組數我們可以推斷出在採用二進位制補碼編碼的情況下各個型別的表示範圍。比如說int的範圍為-2,147,483,648 ~ 2,147,483,647。但是c標準的存在卻提醒我們事實並非總是如此。

c標準規定的各型別整型數的範圍與其典型值有所不同,通常小於其典型值範圍,並且所有有符號型別只要求對稱範圍。例如,int只要求-32767 ~ 32767。雖然我們使用的編譯器會按照系統位數來決定int型別的實際範圍,但是,如果想要使**能夠跨平台,最好按照c標準規定的範圍來設計自己的程式,這樣只要編譯器遵循c標準,**就一定不會出錯。否則,像int i = 99999;這樣的語句,放到16位計算機上就直接溢位了。

接下來提乙個有趣的事情,在32位計算機的標頭檔案中,定義了各個基本資料型別的範圍,以整型為例

#define int_max 2147483647

#define int_min (-int_max-1)

為什麼最小值不直接寫#define int_min -2147483648呢?

因為對編譯器來說,-2147483648是乙個表示式,它的意思是對2147483648取負。但是2147483648這個數已經超出了整型數所能表示的範圍,因此這樣寫是沒有意義的。更詳細的解釋可以檢視後面的參考資料。

資料型別既有不同的範圍,又有不同的符號性質,當兩者同時轉換時,就需要多加注意。

例如,從short轉換到unsigned需要分兩步,實際過程相當於(unsigned)(int),而不是(unsigned)(unsigned short)。也就是說,先擴大範圍,再改變符號性質。對於下面的**

short s = -12345;

unsigned u = s;

printf("%u\n", u);

unsigned u1 = (unsigned)(int) s;

printf("%u\n", u1);

unsigned u2 = (unsigned)(unsigned short) s;

printf("%u\n", u2);

列印結果uu1都是4294954951,而u253191

深入理解計算機作業系統(2 2 4)

在c語言中,對於有符號數和無符號數之間的轉換是從位級的角度來考慮的而不是從數級的角度來考慮的。簡單說就是,對於有符號數和無符號數之間的轉換,我們希望的是在可以表示的範圍內,數值表示不變,但是c語言中,是二進位制位不變,改變解釋二進位制位的方式。舉例 乙個8位的無符號數128,二進位制位是100000...

深入理解計算機作業系統(九)

本文將介紹儲存器層次結構以及區域性性對程式效能的影響。什麼是儲存器層次結構?區域性性 這個詞大家也許並不陌生,計算機中的儲存器從暫存器 快取到記憶體 硬碟,形成了乙個層次結構。為什麼不用單一的一種儲存裝置,比如只用硬碟呢?因為每一種儲存裝置都有它的優缺點,硬碟雖然儲存空間大,但傳輸速率太慢,完全跟不...

深入理解計算機作業系統(1) 鏈結器

鏈結是將各種 和資料片段收集起來組合成為乙個單一檔案的過程。可能發生在編譯 載入到記憶體 程式執行時候。首先使用預編譯器將mian.cpp翻譯成main.i ascii碼的中間檔案 再使用編譯器翻譯成main.s 彙編檔案 再使用彙編器翻譯成可重定位目標檔案main.o,最後使用鏈結器將main.o...