1.1 CPU內部結構解析
程序是計算機進行每一步動作的一組指令,程序由指令+數據組成。
機器語言是CPU可以直接識別並且能夠直接使用的語言,由二進制代碼0和1組成。
正在運行的程序被存儲在內存中,表示命令和數據存儲位置的數值。
CPU是由運算器(運算從內存讀入寄存器的值)、控制器(把內存中的指令和數據讀入寄存器,並根據指令的結果控制整個計算機)、時鍾(負責CPU開始計時的時鍾信號--單位赫茲,Hz,頻率越高,CPU運行速度越快)和寄存器(暫存指令、數據等處理對象)這四部分組成。
內存負責存儲指令+數據,DRAM(dynamic random access memory)動態隨機存儲器。其特點是運行速度快,斷電數據丟失。
程序的運行機制:程序運行后,根據時鍾信號,控制器會將內存中的指令和數據讀入到寄存器中,運算器負責運算這些讀入到寄存器中的數據,控制器根據運算器所得的結果進而控制計算機。
1.2 CPU是寄存器的集合體
我們通過1.1中對程序的運行機制的了解,我們會發現程序的運行過程其實就是和寄存器不斷打交道的過程,因此也就不難理解CPU就是寄存器的集合體這句話了。我們根據寄存器的不同功能,大致可以將寄存器分為八大類別:CPU內只有1個的-->累加寄存器、標指寄存器、程序計數器、指令寄存器、棧寄存器,有多個的-->基址寄存器、變址寄存器、通用寄存器。此處大家只需了解寄存器大致分為這八類即可,對於這些寄存器的具體作用等到后邊具體使用的時候我在詳細介紹哈。
上圖中白色字體表示CPU中該寄存器只有一個,藍色字體代表該寄存器有多個。
1.3 決定程序流程的程序計數器
CPU的控制器會參照程序計數器的數值,從相應的內存中讀取指令和數據並執行與之對應的程序。
1.4 順序執行和循環機制
順序執行時程序計數器每執行一次自動+1,跳轉指令時則執行jump指令跳轉到指定的地址。
1.5函數的調用機制
在講解函數調用機制之前,我們先來比較一下 跳轉指令&函數調用的不同之處
表面上,兩者的實現方式貌似相似——都是根據程序計數器設定的值跳轉到指定的地址處執行程序,但是在內存中的實際執行機制上邊卻又是完全不同,一下舉兩個簡單的小栗子哈
跳轉指令:
1 int main() 2 { 3 int a = -5; 4 //下一條指令的地址
5 if (a >= 0) 6 { 7 printf("%d\n",a); 8 } 9 else
10 { 11 a = -a; 12 printf("%d\n",a); 13 } 14 return 0; 15 }
我們不難看出,程序執行的順序是1--2--3--4--5--11--12--14,在執行跳轉指令之前,如果第四行有程序則會先去執行第四行的程序。
而函數執行卻與此不同
1 #include <stdio.h>
2 int add(int a,int b) 3 { 4 return a + b; 5 } 6 int main() 7 { 8 int a = 10; 9 int b = 20; 10 int c = add(a,b); 11 printf("%d\n", c); 12 return 0; 13 }
由於main()函數是程序的入口,因此該程序的執行順序是7-->8-->9-->10-->4-->5-->10-->11-->12-->13
細心的你或許就會發現,跳轉指令和函數調用還是有區別的。事實上,在內存中,跳轉指令執行的是jump指令,它所要關心的只是所要跳轉的地址,而不關心返回的問題。但是函數調用就不一樣了,它不僅要關注所要調用的地址,還要有返回的問題,其實,在內存中函數調用執行的是call指令,call指令會先把調用結束后要執行的下一條指令的地址存儲在內存的棧里邊去,然后根據棧先進后出的特點,函數在調用完畢之后便會從內存中釋放掉,也就是所謂的出棧,此時便可以通過函數的出口執行return指令,該指令的作用就是將下一條指令的地址的值設定到程序計數器中。
1.6 通過地址和索引實現數組
在此之前介紹兩個寄存器——基址寄存器和變址寄存器,以及進制的表示方法。
基址寄存器:存儲數據內存的起始地址;
變址寄存器:存儲基址寄存器的相對地址。
進制的表示方法:4位二進制可以表示的范圍是 0000~1111 ,轉化成十進制所表示的范圍就是 0~16 (0 1 2 3 4 5 6 7 8 9 10 A B C D E F),其中A B C D E F這幾個字母不區分大小寫表示的數值是11 、12、13、14、15、16,因此1個16進制的數由4個2進制數表示。那么,在32位機器上便能夠表示的內存地址就是00000000 00000000 00000000 00000000 ~ 11111111 11111111 11111111 11111111,此處為了方便沃恩用十六進制表示:0000 0000 ~ FFFF FFFF。則可以通過這種方法模擬出數組的操作:將1000 0000存入基址寄存器(固定值),將 0000 0000 ~ 0000 FFFF之間的值存入到變址寄存器中,那么基址寄存器+變址寄存器的值便是訪問內存的實際地址。
理解了這樣的存儲方式,也就不難理解為什么我們在訪問數組元素的時候第一個元素的下標是0了。
所以,CPU的處理並不是特別的復雜,機器語言的主要類型大致可以分為四類:
- 數據傳送指令
- 運算指令
- 跳轉指令
- call / return 指令
以上便是第一章的讀書筆記和心得體會,由於筆者水平有限,篇幅中難免有紕漏之處,也歡迎各位讀者批評指正。