程序是怎樣跑起來的

程序是怎樣跑起來的

本文主要學(xué)習(xí)自 《c程序是怎樣跑起來》一書凿将,再添加了一些自己的理解和注釋,請(qǐng)各位觀者支持原版

CPU 對(duì)于程序員的意義

  • 指示計(jì)算機(jī)每一步動(dòng)作的一組指令叫做程序价脾,程序是由指令和數(shù)據(jù)構(gòu)成的牧抵,
  • 正在運(yùn)行的程序是存儲(chǔ)在內(nèi)存中的,磁盤和硬盤等媒介中保存的程序被復(fù)制到內(nèi)存后才能運(yùn)行侨把,
  • 內(nèi)存中犀变,用來表示命令和數(shù)據(jù)存儲(chǔ)位置的數(shù)值叫做內(nèi)存地址,地址由整數(shù)值來表示. CPU 負(fù)責(zé)程序的解釋和運(yùn)行秋柄。
  • CPU 能夠識(shí)別和執(zhí)行的只有機(jī)器語言获枝,使用C 或者 Java.編寫的代碼,最終都會(huì)被轉(zhuǎn)化成機(jī)器語言骇笔。

作為一個(gè)程序員只知道 CPU 是中央處理器是不夠的省店,還需要知道 CPU 是如何運(yùn)行的,特別是要弄清楚負(fù)責(zé)保存指令和數(shù)據(jù)的寄存器的機(jī)制笨触,了解了寄存器萨西,就會(huì)理解程序的運(yùn)行機(jī)制。

CPU 的內(nèi)部結(jié)構(gòu)解析

程序運(yùn)行的一般流程

  1. 程序員用 C 語言等高級(jí)語言編寫程序
int a;
a = 1+2;
printf("%d",a);
  1. 將程序編譯后轉(zhuǎn)換成機(jī)器語言的 EXE 文件
010000101001010101010010101010100101010101010010101
  1. 程序運(yùn)行時(shí)旭旭,在內(nèi)存中生成 EXE 文件的副本
  2. cpu 解釋并執(zhí)行程序內(nèi)容

CPU 內(nèi)部組成

屏幕快照 2017-07-07 下午12.50.07.png
寄存器

用來暫存指令谎脯,數(shù)據(jù)等處理對(duì)象,可以將它看成內(nèi)存持寄,一個(gè) CPU 內(nèi)部?jī)?nèi)部會(huì)有 20-100 個(gè)寄存器

控制器

負(fù)責(zé)把內(nèi)存上的指令源梭,數(shù)據(jù)讀入寄存器,并根據(jù)指令的執(zhí)行結(jié)果來控制整個(gè)計(jì)算機(jī)稍味。废麻、

運(yùn)算器

負(fù)責(zé)運(yùn)算從內(nèi)存讀入寄存器的數(shù)據(jù)

時(shí)鐘

負(fù)責(zé)發(fā)出 CPU 開始計(jì)時(shí)的時(shí)鐘信號(hào)

內(nèi)存

通常說的內(nèi)存是指計(jì)算機(jī)的主存儲(chǔ)器,簡(jiǎn)稱 主存模庐,主存通過控制芯片等與 cpu 相連烛愧,主要負(fù)責(zé)存儲(chǔ)指令和數(shù)據(jù),主存由可讀寫的元素構(gòu)成,每個(gè)字節(jié)(1個(gè)字節(jié) =8 位)都帶有一個(gè)地址編號(hào)怜姿,CPU 可以通過改地址讀取主存中的指令和數(shù)據(jù)慎冤,當(dāng)然也可以寫入數(shù)據(jù),但是需要注意的是沧卢,主存中存儲(chǔ)的指令和數(shù)據(jù)會(huì)隨著計(jì)算機(jī)的關(guān)機(jī)而自動(dòng)清除蚁堤。

程序的運(yùn)行機(jī)制:程序啟動(dòng)后,根據(jù)時(shí)鐘信號(hào)但狭,控制器會(huì)從內(nèi)存中讀取指令和數(shù)據(jù)披诗,通過這些指令加以解釋和運(yùn)行,運(yùn)算器會(huì)對(duì)數(shù)據(jù)進(jìn)行運(yùn)算立磁,控制器根據(jù)該運(yùn)算結(jié)果來控制計(jì)算機(jī)(所謂的控制就是值數(shù)據(jù)運(yùn)算以外的處理,比如:數(shù)據(jù)輸入和輸出事件的控制呈队,鍵盤,顯示器等的輸入輸出唱歧。)

CPU 是寄存器的集合體

CPU 的四個(gè)構(gòu)成部分中宪摧,其實(shí)我們只需要了解寄存器即可。原因是:程序把寄存器作為對(duì)象來描述的迈喉。

備注: 內(nèi)存的存儲(chǔ)場(chǎng)所通過地址編號(hào)來區(qū)分五慈,而寄存器的種類則通過名字來區(qū)分水泉。

屏幕快照 2017-07-07 下午1.06.08.png

通池罢可以將寄存器分為8類:

  • 累加寄存器: 存儲(chǔ)執(zhí)行運(yùn)算的數(shù)據(jù)和運(yùn)算后的數(shù)據(jù) (1個(gè))
  • 標(biāo)志寄存器: 存儲(chǔ)運(yùn)算處理后的 CPU 狀態(tài) (1個(gè))
  • 程序計(jì)數(shù)器: 存儲(chǔ)下一條指令所在的內(nèi)存的地址 (1個(gè))
  • 基址寄存器: 存儲(chǔ)數(shù)據(jù)內(nèi)存的起始地址
  • 變址寄存器: 存儲(chǔ)基址寄存器的相對(duì)地址
  • 通用寄存器: 存儲(chǔ)任意數(shù)據(jù)
  • 指令寄存器: 存儲(chǔ)指令俭令, CPU 內(nèi)部使用幻枉,程序員無法通過程序?qū)υ摷拇嫫鬟M(jìn)行讀寫操作箕母。(1個(gè))
  • 棧寄存器: 存儲(chǔ)棧區(qū)域的起始地址 (1個(gè))

決定程序流程的程序計(jì)數(shù)器

順序執(zhí)行程序
屏幕快照 2017-07-07 下午1.11.37.png
條件分枝和循環(huán)機(jī)制

程序的流程分為: 順序執(zhí)行赢赊,條件分枝和循環(huán)三種鹅心,順序執(zhí)行:是指按照地址內(nèi)容的順序執(zhí)行指令锅移,條件分枝:是指根據(jù)條件執(zhí)行任意地址的指令熔掺,循環(huán): 是指重復(fù)執(zhí)行同一地址的指令。

屏幕快照 2017-07-07 下午1.15.26.png

CPU 在進(jìn)行運(yùn)算時(shí)非剃,標(biāo)志寄存器的數(shù)值會(huì)根據(jù)運(yùn)算結(jié)果自動(dòng)設(shè)定置逻,至于是否執(zhí)行跳轉(zhuǎn)指令,則由 CPU 在參考標(biāo)志寄存器的數(shù)值后進(jìn)行判斷

cpu 執(zhí)行比較的機(jī)制:將要比較的兩個(gè)寄存器中的數(shù)據(jù)做減法备绽,得到的結(jié)果保存到標(biāo)志寄存器中券坞,判斷正負(fù)。

函數(shù)的調(diào)用機(jī)制

函數(shù)的調(diào)用是通過把程序計(jì)數(shù)器的值設(shè)定成函數(shù)的存儲(chǔ)地址來實(shí)現(xiàn)肺素。函數(shù)的調(diào)用需要再完成函數(shù)內(nèi)部的處理后恨锚,處理流程在返回到函數(shù)的調(diào)用點(diǎn)(函數(shù)調(diào)用指令的下一個(gè)地址),因此倍靡,如果只是跳轉(zhuǎn)到函數(shù)的入口地址猴伶,處理流程就不知道應(yīng)該返回至哪里了。

機(jī)器語言的 call 指令和 return 指令能夠解決這個(gè)問題解決當(dāng)函數(shù)調(diào)用后執(zhí)行的返回。函數(shù)調(diào)用使用的是 call 指令 而不是跳轉(zhuǎn)指令他挎,在將函數(shù)的入口地址設(shè)定到程序計(jì)數(shù)器之前筝尾, call 指令會(huì)把調(diào)用函數(shù)后要執(zhí)行的指令地址存儲(chǔ)在名為棧的主存中,函數(shù)處理完畢后雇盖,再通過函數(shù)的出口來執(zhí)行 return 命令忿等, return 命令的功能是把保存在棧中的地址設(shè)定到程序計(jì)數(shù)器中。

屏幕快照 2017-07-07 下午1.38.55.png

具體請(qǐng)參考我稍后會(huì)帶來的遞歸算法的處理原理

通過地址和索引實(shí)現(xiàn)數(shù)組

通過基址寄存器變址寄存器可以對(duì)主存上特定的內(nèi)存區(qū)域進(jìn)行劃分崔挖。從而實(shí)現(xiàn)類似于數(shù)組的操作贸街。

如果想要像數(shù)組一樣分割特定的內(nèi)存區(qū)域以達(dá)到連續(xù)查看的目的,使用兩個(gè)寄存器會(huì)更方便些狸相。 CPU 會(huì)把 基址寄存器 + 變址寄存器的值解釋為實(shí)際查看的內(nèi)存地址薛匪,變址寄存器的值就相當(dāng)于變成語言中數(shù)組的索引。

機(jī)器語言的主要類型和功能

屏幕快照 2017-07-07 下午1.46.26.png

數(shù)據(jù)是通過二進(jìn)制表示的

原碼脓鹃,反碼逸尖,補(bǔ)碼,移碼

正數(shù): 反碼 = 原碼 = 補(bǔ)碼

負(fù)數(shù): 反碼 = 其原碼除符號(hào)之外的各位求反
補(bǔ)碼 = 反碼 + 1

運(yùn)算實(shí)例

正零: 00000000
負(fù)零: 10000000

補(bǔ)碼:
00000000 11111111+1 -> 00000000

需要注意的是:如果 +1 之后有進(jìn)位瘸右,要一直往前進(jìn)位娇跟,包括符號(hào)位。

例如:

原碼: 01011
反碼: 01011
補(bǔ)碼: 01011

原碼: 11011
反碼: 10100
補(bǔ)碼: 10101

在計(jì)算機(jī)中太颤,數(shù)據(jù)一律通過補(bǔ)碼來存儲(chǔ)

使用補(bǔ)碼的原因

學(xué)習(xí)自 原碼苞俘、反碼和補(bǔ)碼, 補(bǔ)碼、負(fù)數(shù)和減法

我總結(jié)一下大概的原因如下:

  • 計(jì)算機(jī)里面只有加法器龄章,沒有減法器吃谣,所有的減法都必須使用加法來進(jìn)行。
  • 所謂的補(bǔ)碼算法是有編譯器在編譯的時(shí)候處理負(fù)數(shù)用的做裙。
  • 使用補(bǔ)碼的原因是模運(yùn)算. 具體可以解釋為 補(bǔ)碼 = 模 - |X|
  • 模 1 + 運(yùn)算位數(shù)個(gè)0
  • 將二進(jìn)制的值求反后加1的結(jié)果和原來的值相加岗憋,結(jié)果為0.

數(shù)值,字符串和圖像信息在計(jì)算機(jī)內(nèi)都是以二進(jìn)制數(shù)值的形式來表現(xiàn)的

用二進(jìn)制表示計(jì)算機(jī)信息

原因

IC 是集成電路锚贱,IC 的引腳只有良種繁育狀態(tài) 0V 和 5V, 也就是說仔戈,一個(gè)引腳只能表示兩個(gè)狀態(tài)。這種特性決定了計(jì)算機(jī)只能使用二進(jìn)制數(shù)來處理信息數(shù)據(jù)拧廊。

屏幕快照 2017-07-07 下午3.23.32.png

字節(jié)是最基本的信息計(jì)量單位杂穷,位是最小單位,字節(jié)是基本單位卦绣。

除法運(yùn)算和移位運(yùn)算的關(guān)系

移位運(yùn)算就是將二進(jìn)制數(shù)值的各數(shù)位進(jìn)行左右移動(dòng)的運(yùn)算耐量,移位有左移和右移兩種,再一次運(yùn)算中滤港,可以進(jìn)行多個(gè)數(shù)位的移位操作廊蜒。

計(jì)算機(jī)進(jìn)行小數(shù)運(yùn)算時(shí)出錯(cuò)的原因

舉例查看

        float sum;
        int i;

        sum = 0;
        for (i = 0; i <100; ++i)
        {
                sum += 0.1;
        }

        printf("%f\n", sum);

打印出來竟然是 10.000002, 而不是10.
原因是什么呢趴拧,下面就來分析分析

用二進(jìn)制數(shù)表示小數(shù)

1011.0011 -- 十進(jìn)制 --> 11.1875

計(jì)算機(jī)運(yùn)算出錯(cuò)的原因

計(jì)算機(jī)之所以會(huì)出現(xiàn)運(yùn)算錯(cuò)誤的原因是因?yàn)橐恍┬?shù)無法轉(zhuǎn)換二進(jìn)制數(shù),例如上述的 0.1 山叮,就無法用二進(jìn)制數(shù)正確表示著榴,小數(shù)點(diǎn)后面即使有幾百位也無法表示。

內(nèi)存

高級(jí)語言中數(shù)據(jù)類型表示的是: 占據(jù)內(nèi)存區(qū)域的大小和存儲(chǔ)在該區(qū)域的數(shù)據(jù)類型

計(jì)算中是進(jìn)行數(shù)據(jù)處理的設(shè)備屁倔,而程序表示的就是處理順序和數(shù)據(jù)結(jié)構(gòu)脑又,由于處理對(duì)象數(shù)據(jù)是存儲(chǔ)在內(nèi)存和磁盤上的,因此程序必須能自由地使用內(nèi)存和磁盤锐借。

內(nèi)存的物理機(jī)制

內(nèi)存實(shí)際上是一種名為內(nèi)存 IC 的電子元件问麸,內(nèi)存 IC 中有電源,地址信號(hào)钞翔,數(shù)據(jù)信號(hào)严卖,控制信號(hào)等用于輸入輸出的大量引腳(IC 的引腳),通過為其制定地址布轿,來進(jìn)行數(shù)據(jù)的讀寫哮笆。

屏幕快照 2017-07-07 下午3.23.32.png
屏幕快照 2017-07-07 下午5.13.44.png

內(nèi)存的邏輯

雖然內(nèi)存的實(shí)體是內(nèi)存 IC, 但是在程序員眼里的內(nèi)存模型中,還包含著物理內(nèi)存中不存在的概念-> 數(shù)據(jù)類型汰扭。

編程語言中的數(shù)據(jù)類型表示存儲(chǔ)的是何種類型的數(shù)據(jù)稠肘,從內(nèi)存上來看,就是占用的內(nèi)存大小,即使是物理上以字節(jié)為單位來逐一讀寫的數(shù)據(jù)的內(nèi)存萝毛,在程序中项阴,通過為其制定類型,也能實(shí)現(xiàn)以特定字節(jié)數(shù)為單位來進(jìn)行讀寫珊泳。

char a;
short b;
long c;

a = 123;
b = 123;
c = 123;

這三個(gè)變量的數(shù)據(jù)都是123鲁冯,但所占用的內(nèi)存不一樣拷沸,

屏幕快照 2017-07-07 下午5.20.37.png

指針

指針是 C 語言的重要特征色查,理解指針的關(guān)鍵點(diǎn)是弄清楚數(shù)據(jù)類型這個(gè)概念。

指針也是一種變量撞芍,他所表示的不是數(shù)據(jù)的值秧了,而是存儲(chǔ)著數(shù)據(jù)的內(nèi)存的地址,通過使用指針序无,就可以對(duì)任意地址的數(shù)據(jù)進(jìn)行讀寫验毡。

char *d;
short *e;
long *f;

假設(shè) d,e,f 的值都是 100, 再這種情況下,使用 d 時(shí)就能夠從編號(hào) 100 的地址讀寫1個(gè)字段帝嗡,使用 e 時(shí)就是兩個(gè)字段晶通,f 就是4個(gè)字節(jié)。

數(shù)組是高效實(shí)用內(nèi)存的基礎(chǔ)

數(shù)組是多個(gè)同樣數(shù)據(jù)類型的數(shù)據(jù)在內(nèi)存中連續(xù)排列的形式哟玷,作為數(shù)組元素的各個(gè)數(shù)據(jù)會(huì)通過連續(xù)的編號(hào)被區(qū)分開來狮辽。這個(gè)編號(hào)稱為索引一也。制定索引后,就可以對(duì)該索引所對(duì)應(yīng)的地址的內(nèi)存進(jìn)行讀寫操作喉脖,而索引和內(nèi)存地址的變換工作則是由編譯器自動(dòng)實(shí)現(xiàn)的椰苟。

之所以說 數(shù)組是內(nèi)存的使用方法的基礎(chǔ),是因?yàn)閿?shù)組和內(nèi)存的物理構(gòu)造是一樣的树叽。

棧舆蝴,隊(duì)列以及環(huán)形緩沖區(qū)

棧和隊(duì)列,都可以不通過制定地址和索引來對(duì)數(shù)組的元素進(jìn)行讀寫题诵,需要臨時(shí)保存計(jì)算過程中的數(shù)據(jù)洁仗,連接在計(jì)算機(jī)上的設(shè)備或者輸入輸出的數(shù)據(jù)時(shí),都可以通過這些方法來使用內(nèi)存.

棧和隊(duì)列的區(qū)別就是數(shù)據(jù)出入的順序是不同的仇轻,在對(duì)內(nèi)存數(shù)據(jù)進(jìn)行讀寫時(shí)京痢,棧使用先進(jìn)后出,隊(duì)列使用先進(jìn)先出篷店。

隊(duì)列一般是以環(huán)形緩沖區(qū)的方式來實(shí)現(xiàn)的祭椰。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市疲陕,隨后出現(xiàn)的幾起案子方淤,更是在濱河造成了極大的恐慌,老刑警劉巖蹄殃,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件携茂,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡诅岩,警方通過查閱死者的電腦和手機(jī)讳苦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吩谦,“玉大人鸳谜,你說我怎么就攤上這事∈酵ⅲ” “怎么了咐扭?”我有些...
    開封第一講書人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)滑废。 經(jīng)常有香客問我蝗肪,道長(zhǎng),這世上最難降的妖魔是什么蠕趁? 我笑而不...
    開封第一講書人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任薛闪,我火速辦了婚禮,結(jié)果婚禮上俺陋,老公的妹妹穿的比我還像新娘豁延。我一直安慰自己怀各,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開白布术浪。 她就那樣靜靜地躺著瓢对,像睡著了一般。 火紅的嫁衣襯著肌膚如雪胰苏。 梳的紋絲不亂的頭發(fā)上硕蛹,一...
    開封第一講書人閱讀 51,462評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音硕并,去河邊找鬼法焰。 笑死,一個(gè)胖子當(dāng)著我的面吹牛倔毙,可吹牛的內(nèi)容都是我干的埃仪。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼陕赃,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼卵蛉!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起么库,我...
    開封第一講書人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤傻丝,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后诉儒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體葡缰,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年忱反,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了泛释。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡温算,死狀恐怖怜校,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情米者,我是刑警寧澤韭畸,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布宇智,位于F島的核電站蔓搞,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏随橘。R本人自食惡果不足惜喂分,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望机蔗。 院中可真熱鬧蒲祈,春花似錦甘萧、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至酸钦,卻和暖如春怪得,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背卑硫。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工徒恋, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人欢伏。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓入挣,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親硝拧。 傳聞我的和親對(duì)象是個(gè)殘疾皇子径筏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容