核心觀點:型別約定了對資料的解釋方式
資訊和資料
來自 wikipedia 的定義
wikipedia 上的定義真的是太晦澀了
在我的理解中,資料就是不帶有任何屬性的數字。例如一個數字1,就是一個單純的資料。
僅通過一個數字 1,你是無法得到任何資訊的,因為你不知道這個1到底代表什麼意思。只有結合具體的語境,你才能從中獲得有用的資訊。
例如1本書、1個人、1頭豬等等
上面的書、人、豬實際上就是對資料的解釋方式。他們分別將 1 解釋為書的數量、人的數量、豬的數量。
因此為了獲取資訊,除了知道資料本身外,你還得需要知道對資料的解釋方式。
所以,資訊 = 資料 + 資料的解釋方式
想一想諜戰片子裡面的電報機,電報機所傳送的實際上是一些長短不一的摩爾斯電碼,這些摩爾斯電碼就是資料,外部人員不知道這些電碼代表的是啥,但是專業的諜報人員對其翻譯後,就可以從其中獲取到有用的資訊。這裡的翻譯實際上就是在對資料進行解釋。翻譯工作可能是依靠一個密碼本來進行的,密碼本上約定了資料的解釋方式。
例子
l i v e
這四個字母,如果用從左至右的方式來解釋,將是 live,如果用從右至左的方式來解釋,將是 evil。
1 0 1 1
這四個數字,如果每兩個一組進行解釋,將會得到
10 11
如果每四個一組進行解釋,將會得到
1011
同樣的資料,使用不同的解釋方式,就能得到不一樣的資訊。
型別約定了對資料的解釋方式
c 語言中有如下一些基礎資料型別,摘自https://www.runoob.com/cprogramming/c-data-types.html
整數型別
型別 | 儲存大小 | 值範圍 |
---|---|---|
char | 1 位元組 | -128 到 127 或 0 到 255 |
unsigned char | 1 位元組 | 0 到 255 |
signed char | 1 位元組 | -128 到 127 |
int | 2 或 4 位元組 | -32,768 到 32,767 或 -2,147,483,648 到 2,147,483,647 |
unsigned int | 2 或 4 位元組 | 0 到 65,535 或 0 到 4,294,967,295 |
short | 2 位元組 | -32,768 到 32,767 |
unsigned short | 2 位元組 | 0 到 65,535 |
long | 4 位元組 | -2,147,483,648 到 2,147,483,647 |
unsigned long | 4 位元組 | 0 到 4,294,967,295 |
浮點型別
型別 | 儲存大小 | 值範圍 | 精度 |
---|---|---|---|
float | 4 位元組 | 1.2E-38 到 3.4E+38 | 6 位小數 |
double | 8 位元組 | 2.3E-308 到 1.7E+308 | 15 位小數 |
long double | 16 位元組 | 3.4E-4932 到 1.1E+4932 | 19 位小數 |
再回顧一下我的核心觀點:型別約定了對資料的解釋方式
在這裡我就取 char 型別和 short 型別來解釋。char 型別的大小是 1 位元組,short 型別的大小是 2 位元組。一位元組 byte 等於 8 bit,一個 bit 就是一個二進位制位,值為 0 或 1。實際上 char 約定了以 8 個 bit 為一組來解釋,而 short 則約束了以 16 個 bit 為一組來解釋。
現在有一個 16 個 bit 大小的空間,空間裡的內容為:
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
如果用 char (每 8 個 bit 為一組)來解釋,則可以解釋為兩個 char,char0 = 00000000 = 0,char1 = 00000001 = 1。
如果用 short (每 16 個 bit 為一組)來解釋,則可以解釋為 1 個 short,short0 = 0000000000000001 = 1。
變數(variable) = 地址(address) + 型別(type)
一個變數由兩個要素組成,分別是變數的地址,以及變數的型別。
address 確定了存放變數的字面值的空間位置
type 約定了如何解釋這段空間
在 c 語言中,初始化一個變數的方式是:
char a = 1;
例如在這裡,
- 變數 a 的 address 是 &a
- 型別是 char,它決定了將會以 8 個 bit 為單位解釋 address 中的內容
- a 的字面值是 1,字面值是通過 address 和 char 通過得到的
在 address 處存放了資料本體,利用 type 來解釋資料,最終得到字面值這個資訊。
對變數的訪問是通過訪問該變數的地址來完成的
在 c 語言中,對於變數的訪問實際上都是通過訪問該變數的地址來完成的。但是隻有地址還不夠,如何解釋這篇地址的內容,是以 8 個 bit 為單位亦或者是以 16 個 bit 為單位,這就需要用到型別了。
變數在初始化時,會被分配一個地址。這個地址就是變數的家,變數的地址是不會發生改變的,它一輩子只會有一個家,不會搬家。
變數的初始化
char c = 1;
在這行程式碼裡,實際上會有如下兩步操作:
-
為變數 c 分配一個空間,這個空間就是 c 的家,假設 c 住在地球一號村,二號樓0號房間吧,就用 0x120 來表示 c 的地址吧。
-
將 0x120 ~ 0x128 這 8 個 bit 的空間裡的內容初始化為 1(其實 c 裡面地址的單位是 1 個 byte,而非 bit),變成下面這個樣子:
為何是 8 個 bit 而不是其他數字的 bit?這是 c 的型別所決定的,因為型別是 char,所以是 8 個 bit。
對 c 的修改
c = 2
實際上還是分為兩步:
-
第一步還是先得到 c 的地址,之前說過變數的地址是不會傳送改變的,因此這裡變數 c 的地址也就是 0x120
-
將 0x120 ~ 0x128 這 8 個 bit 的空間裡的內容初始化為 2,變成了下面這樣:
對 c 的訪問
char i = c;
- 得到 c 的地址 0x120
- 對 0x120 ~ 0x128 這 8 個 bit 大小的空間進行解釋。型別約定了對資料的解釋方式,而這裡的型別是 char,所以用 8 個 bit 的方式來解釋。
- 對 i 的操作也是類似的...
指標
指標變數本質和普通的變數沒有太大區別,依舊由值和型別組成,同樣也會被分配一個地址。
但是它相比普通變數多了一個 *
(dereference) 操作。dereference 是指標變數所特有的操作,普通的變數是無法進行 dereference 操作的,否則會發生編譯錯誤。
定義一個指標變數
char* p = 0x120;
p 的值是 0x120 ,p 的型別是 char* (指向 char 型別的指標)。
char* = char + *
* 表明這個變數是一個指標,因此有 dereference 能力
char 約定了在 dereference 時,它將會以 8 個 bit為 單位來解釋
deference
通過 dereference ,可以對地址中的內容進行操作。
*p = 1
這句程式碼將會把 0x120 ~ 0x128 這 8 個 bit 的空間裡的內容置為 1。
對指標變數的修改
p = 2
與上面所說的變數的修改過程是一樣。
一些具體的例子
基本原則
- 變數 = address + type
- 變數會被分配一個地址,且這個地址是固定的
- 對變數的訪問是通過訪問變數的地址來完成的,變數的型別約定了對地址中內容的解釋方式
例子1:通過指標來修改變數的值
char c = 1; // 為 c 分配地址,假設 c 的地址是 0x120,c 的值是 1,0x120 ~ 0x128 這 8 個 bit 的內容是 1
char* pc = &c; // pc 是一個指標,它的值是 c 的地址,則 pc 的值是 0x120
*pc = 2; // dereference 操作,將 0x120 ~ 0x128 這 8 個 bit 的內容設定為 2
printf("%d",c); // 取 0x120 ~ 0x128 這 8 個 bit 的內容進行解釋,得到 2,因此輸出 2
例子2:指向指標的指標
char* pc = null; // 為 pc 分配地址,假設 pc 的地址是 0x1200,pc 的值是 0,0x1200 ~ 0x1220 這 32 個 bit 的內容是 0(在 32 為環境下,指標的大小是 32 bit)
char** ppc = &pc; // ppc 的值為 0x1200
char c = 1; // 為 c 分配地址,假設 c 的地址是 0x120,c 的值是 1,0x120 ~ 0x128 這 8 個 bit 的內容是 1
*ppc = &c; // 將 0x1200 ~ 0x1220 這 32 個 bit(char*) 的內容設定為 0x120,此時 pc 的值為 0x120 了
*pc = 2; // 取 0x120 ~ 0x128 這 8 個 bit(char) 的內容設定為 2, 此時 c 的值變成 2 了