1.信息的存儲(chǔ)
- 通常情況下,程序?qū)?nèi)存視為一個(gè)非常大的數(shù)組。數(shù)組的元素是由一個(gè)個(gè)的字節(jié)組成,每個(gè)字節(jié)都由一個(gè)唯一的數(shù)字來(lái)表示,稱之為地址。這些所有地址的集合稱為虛擬地址空間。

信息的存儲(chǔ).jpg
2.字節(jié)
- 1個(gè)字節(jié)是由8個(gè)位組成,在二進(jìn)制中,每一位的值可能有0或者1兩種狀態(tài)。當(dāng)這8個(gè)位全為0時(shí),表示一個(gè)字節(jié)的最小值;當(dāng)這8個(gè)位全為1時(shí),表示最大值;如果用十進(jìn)制來(lái)表示,那么一個(gè)字節(jié)的取值范圍就在[0,255]之間。上面這種按照一位一位表示數(shù)據(jù)的方式稱為位模式。

位模式.jpg
3.十六進(jìn)制表示位模式
- 在C語(yǔ)言中,十六進(jìn)制數(shù)是以0X或0x開(kāi)頭。字母部分可以是全部大寫(xiě)或全部小寫(xiě)或者大小寫(xiě)混合。

十六進(jìn)制、二進(jìn)制、十進(jìn)制.jpg
- 二進(jìn)制與十六進(jìn)制之間的轉(zhuǎn)換:將二進(jìn)制數(shù)從右向左,每四位為一組來(lái)轉(zhuǎn)換成相應(yīng)的十六進(jìn)制數(shù)。如果總位數(shù)不是4的倍數(shù),那么最左邊的一組會(huì)出現(xiàn)小于4位的情況,這時(shí)將前面進(jìn)行補(bǔ)0。接著,將每4位為一組的二進(jìn)制數(shù)進(jìn)行一一轉(zhuǎn)換即可得到十六進(jìn)制數(shù)。

二進(jìn)制與十六進(jìn)制轉(zhuǎn)換.jpg
- 如何將形如2的n次方的數(shù)快速轉(zhuǎn)換為二進(jìn)制數(shù)?
2^0 = 1 0個(gè)0
2^1 = 10 1個(gè)0
2^2 = 100 2個(gè)0
2^3 = 1000 3個(gè)0
2^4 = 10000 4個(gè)0
2^5 = 100000 5個(gè)0
....
2^n = 1000...000 n個(gè)0
n = i + 4j:n除以4,j是商、i是余數(shù),i的可能取值是0、1、2、3,因此與之對(duì)應(yīng)的十六進(jìn)制數(shù)是1、2、4、8
例如2^13, n = 13 = 1 + 4 * 3,因此2^13 = 0x2000
- 十進(jìn)制與十六進(jìn)制之間的轉(zhuǎn)換:使用輾轉(zhuǎn)相除法,每次使用得到的商來(lái)除以16,直到得到的商不能被16整除為止。將得到的余數(shù)用16進(jìn)制來(lái)表示,然后自下而上書(shū)寫(xiě)即可得到十六進(jìn)制表示。

十進(jìn)制轉(zhuǎn)換成十六進(jìn)制數(shù).jpg
4.字長(zhǎng)Words
- 字長(zhǎng)決定了虛擬地址空間最大值可以到多少,對(duì)于32位機(jī)器,虛擬地址空間最大為4GB;64位機(jī)器,虛擬地址空間最大為16EB。

字長(zhǎng).jpg
- 大多數(shù)64位的機(jī)器做了向下兼容,因此32位機(jī)器編譯的程序也可以運(yùn)行在64位機(jī)器上。在64位機(jī)器上,可以通過(guò)命令gcc -m32 -o hello32 hello.c編譯生成可以在32位機(jī)器上運(yùn)行的程序。通過(guò)修改編譯選項(xiàng)gcc -m64 -o hello64 hello.c,就可以編譯生成在64位機(jī)器上運(yùn)行的程序。

不同類型數(shù)據(jù)占用不同字節(jié)空間.jpg
5.地址和字節(jié)序
- 一個(gè)int類型的變量x=0x01234567,假設(shè)地址位于0x100處。由于int類型占4個(gè)字節(jié),因此x被存儲(chǔ)在地址為0x100~0x103的內(nèi)存處。

大端模式與小端模式.jpg
大端模式:最高有效字節(jié)存儲(chǔ)在最前面即低地址處。IBM和Sun公司的機(jī)器大多采用大端法。
-
小端模式:最低有效字節(jié)存儲(chǔ)在最前面即低地址處。大多數(shù)intel兼容機(jī)采用小端模式。
// 判斷大、小端模式測(cè)試程序 #include <stdio.h> typedef unsigned char* byte_pointer; void show_bytes(byte_pointer start, int len) { int i; for(i = 0; i < len; i++) { printf("%.2x", start[i]); } printf("\n"); } void show_int(int x) { show_bytes((byte_pointer) &x, sizeof(x)); }
6.存儲(chǔ)字符串
- C語(yǔ)言中的字符串被編碼為以NULL字符結(jié)尾的字符數(shù)組,其中結(jié)尾字符的十六進(jìn)制表示為0x00。使用ASCII碼來(lái)表示字符,在任何系統(tǒng)上都會(huì)得到相同的結(jié)果。于是,文本數(shù)據(jù)比二進(jìn)制數(shù)據(jù)具有更強(qiáng)的平臺(tái)獨(dú)立性。

字符串存儲(chǔ).jpg
7.布爾代數(shù)
- C語(yǔ)言中,支持按位進(jìn)行布爾運(yùn)算。具體如下圖所示:

布爾代數(shù).jpg

C語(yǔ)言中的布爾運(yùn)算.jpg
8.位掩碼運(yùn)算
- 對(duì)于操作數(shù)0x89ABCDEF,我們希望得到該操作數(shù)的最低有效字節(jié)的值EF,可以通過(guò)&上0xFF這樣就得到了最低有效字節(jié)0x000000EF;

位掩碼運(yùn)算.jpg
9.邏輯運(yùn)算
- 邏輯運(yùn)算中,所有非零的參數(shù)都表示為true,只有參數(shù)0表示為false。邏輯運(yùn)算的結(jié)果只有兩種true/false,而位運(yùn)算只有在特殊的數(shù)值條件下才會(huì)得到0或者1。

邏輯運(yùn)算.jpg
10.移位運(yùn)算
- 對(duì)于8位二進(jìn)制數(shù)01100011,左移一位就是丟棄最高的1位,并在右端補(bǔ)1個(gè)0,具體結(jié)果如下圖所示:

左移一位.jpg
- 對(duì)于右移運(yùn)算,分為邏輯右移和算術(shù)右移。邏輯右移和邏輯左移只是在方向上存在差異,邏輯右移一位就是丟棄最低的1位,并在左端補(bǔ)一個(gè)0。

邏輯右移一位.jpg
- 對(duì)于算術(shù)右移,以下以10010101為例說(shuō)明。當(dāng)算術(shù)右移的操作對(duì)象的最高位等于0時(shí),算術(shù)右移等于邏輯右移,兩者沒(méi)有任何差別;當(dāng)操作數(shù)的最高位為1時(shí),算術(shù)右移后,左端需要補(bǔ)1而不是補(bǔ)0;

算術(shù)右移且操作數(shù)的最高位等于0.jpg

算術(shù)右移且操作數(shù)的最高位等于1.jpg
- 雖然C語(yǔ)言中并沒(méi)有明確的規(guī)定有符號(hào)數(shù)應(yīng)該使用哪一種類型的右移方式,但實(shí)際上幾乎所有的編譯器以及機(jī)器的組合都是對(duì)有符號(hào)數(shù)使用算術(shù)右移;對(duì)于無(wú)符號(hào)數(shù),右移一定是邏輯右移;
11.參考資料
[1].本文圖片來(lái)源,侵權(quán)必刪:https://www.bilibili.com/video/BV1cD4y1D7uR?p=6