C語言筆記之資料型別(一)

2021-07-02 04:24:19 字數 3254 閱讀 2789

在《計算機眼裡的數字》這篇文章中,我曾提到,位元組是計算機最小的可定址的單位,位址對應的是乙個個位元組,而不是位元組的每個位。這樣編址的原因很簡單——單個的位所能表示的資訊量太少了,只有兩種狀態0和1,只有把足夠多的位組合起來才能表示足夠豐富的資訊。那麼為什麼一定要是8呢?因為大家都這麼做。。。好吧,肯定一定的歷史原因,我就不深究了。

但是,即使是8個位組成的位元組,其所能表示的資訊量仍然是有限的,因為最多只有256中狀態組合,如果用每種狀態對應0~255之間的數字的話,那麼就無法表示256這個數。這時候只好用兩個位元組來表示大於255的數。同樣的道理,當數字大到超過兩個位元組所能表示的數的極限後,就用四個位元組。。。是的,你也發現了,位元組數目總是翻倍增長,為什麼不用3個位元組呢?甚至,為啥不用1.5個位元組呢?對於前者,是因為考慮到對齊的原因,這其中有太多東西要說,我就不展開了;而後者,前面其實說到了,因為沒有位的編址,無法深入到位元組內部把資料揪出來。。所以,儲存肯定會有一定的浪費,在所難免。

上面羅嗦了那麼多,其實只是為了引出本文的豬腳——c語言資料型別,為什麼c語言要分那麼多型別呢?因為對於不同大小的數,所需要的儲存空間大小不同。如果都用4個位元組儲存,那麼肯定不用分資料型別,但是好浪費哦~所以,本著節省記憶體的考慮,資料型別就誕生了。

c的資料型別分為基本資料型別和復合資料型別,後者只是前者的某種組合。基本資料型別按照其在計算機中的儲存方式又分為整數型別和浮點數型別。

一、整數型別

整數型別包括char、short、int、long、long long,它們沒有小數部分。char雖然是字元型別,但是由於儲存的是ascii碼,本質上也是按整數儲存的,所以歸為這一類。不同的整數型別具有不同的位元組數,從而所占用的儲存空間不同。然而,這一點是不確定的,準確的位元組數依賴於具體的機器和編譯器——機器不僅分品牌,還有32位和64位之分。下面的**給出不同型別所占有的典型的位元組數(**《深入理解計算機系統》): 型別

32位機器

64位機器

char11

short22

int 44

long48

long long88

char *48

float44

double88

注意,上表只是典型值,以32位為例:在有的機器上,short和int都是2個位元組,long是4個位元組;而有的機器上,short是2個位元組,而int和long是4個位元組。c語言僅僅規定:short <= int <= long,然後char是1個位元組。不過,對於大部分機器,上表夠用了。要檢視自己機器上每種型別所佔的位元組數,請用sizeof(型別)來檢視。

對於整數型別,c還用了signed和unsigned來修飾它們,以獲得有符號數和無符號數,預設時,認為是有符號數。正如在《計算機眼裡的數字》中提到的那樣,有符號數和無符號數的二進位制表示可能是一樣的,區別僅僅是解讀方式。

有了各種型別之後(即位元組數確定之後),就可以規定它們所表示的數的範圍。下表是32位機器各種型別的典型取值範圍:

signed

unsigned

char

-128 ~ 127

0 ~ 255

short

-32768 ~ 32767

0 ~ 65535

int 

-2147483648 ~ 2147483647

0 ~ 4294967295

long

-2147483648 ~ 2147483647

0 ~ 4294967295

long long

-9223372036854775808 ~ 9223372036854775807

0 ~ 18446744073709551615

這些界限值可以通過包含limits.h標頭檔案加以檢視,比如對於int值的各種範圍,可以通過列印int_max  int_min  

uint_max uint_min 來檢視。

我們用幾個例子來看一下相同型別之間signed和unsigned的轉換。

1、將signed強制轉換成unsigned:

#include int main(void)

執行結果如下:

a = -1, b = -1

a = 4294967295, b = -1

a = -1, b = 4294967295

a = 0xffffffff, b = 0xffffffff

可以明顯的看出,將乙個負數強制轉換為無符號數,並沒有改變其位模式(二進位制表示),它仍然按照原來的模樣儲存,第四行的結果證明了這一點;而前三行的結果表明,即使不做signed到unsigned的強制型別轉換,只需要在列印時改變一下輸出格式,就能達到同樣的效果。(這裡我開始懷疑把乙個變數宣告為unsigned有啥意義?)

而將乙個有符號的正數轉換為同型別的無符號數又如何呢?

2、將unsigned強制轉換成signed:

#include int main(void)

結果如下:

a = 32767, b = 32767

a = 32767, b = 32767

a = 32767, b = 32767

a = 0x7fff, b = 0x7fff

可以看出,當乙個非負數處於0~tmax(tmax代表某一型別有符號數的最大值)的範圍時,無論把它的二進位制表示解讀成signed還是unsigned,結果都是一樣的。這是因為,處於這部分範圍內的數,轉換成二進位制時,最高為都為0,如果按signed解讀,它是乙個正數,數字部分就是7fff,;而按unsigned解讀,07fff == 7fff,結果總是一樣的。

那如果正數的範圍超過了tmax呢?

#include int main(void)

結果:

a = 2147483648, b = -2147483648

a = -2147483648, b = 2147483648

a = 0x80000000, b = 0x80000000

可以看到,底層的二進位制表示仍然是一致的,只是解讀方式發生了變化:由於最高位是1,所以解讀成signed時,是乙個負數;解讀成unsigned仍然是正數,結果不同。

注意:因為變數分為signed和unsigned,對應的常量也要分為signed和unsigned;型別前沒有修飾時,預設為signed,對應的,乙個常量數字預設為signed,即有符號數。如果希望乙個常量數字被當成無符號數,就要在其末尾新增字母'u'或『u』。

C語言筆記之資料型別(二)

接下來是不同型別之間的強制轉換。當把乙個高容量的型別強制轉換為低容量的型別時,會發生截斷 丟棄二進位制的高位,只保留低位 二進位制的左邊為高位,右邊為低位 而把低容量型別強制轉換成高容量型別時,會發生擴充套件 在二進位制的高位左邊繼續填充數字。擴充套件分為兩類 零擴充套件和符號擴充套件。下面看 示例...

C語言資料型別 一

todo 整型 短整型 16位 32767 32767 short si 32767 無符號短整型 16位 0 65535 unsigned short us 65535 printf short hd u short u n si,us 基本整型 32 64位 2147483622 2147483...

C語言筆記 一 基本資料型別

編譯器要處理資料 那麼就需要知道資料的儲存大小和儲存方式 即資料型別 常用的四種基本資料型別 char int float double 小數 浮點型 雙精度浮點型double8個位元組 字元型 字母 浮點型 float double 字元型別 char double存放範圍大 精度高float占用...