03.08 CPU是怎麼認識代碼的?

邢小燕


提前備註:回答比較硬核,我會盡量軟化,但想了解知識還是需要耐心。CPU內傳輸的信號有兩種:高電壓和低電壓,分別代表數字信號“1”和“0”,因此CPU唯一能理解(問題中的“認識”)的語言就是由“1”和“0”寫成的機器語言。

由於程序(代碼)存儲在電腦硬盤中時,也是“1”和“0”的形式,是否就意味著,只要程序存到硬盤中,CPU就能認識呢?

答案是CPU仍然看不懂這些程序,因為以“1”和“0”形式存儲的程序和以“1”和“0”寫成的語言完全是兩回事,兩者的區別類似於漢語書和英語書都用紙和油墨印製,但依然是兩種不同的語言,不會英語的依然看不懂英語書。

要讓CPU能看懂代碼,要做相當多的工作。

現在的程序都是由C++和Java等高級語言寫成,這些語言是為方便人類編程發明的,不是為方便電腦執行而設計。

說到這裡,需要進一步說說機器語言和高級語言的差別。機器語言的最大特點是面向計算機硬件編程,簡單說就是程序員需要通曉計算機硬件知識,寫的程序要真實表示數據是如何被計算機操縱的。對程序員來說這就比較頭大,畢竟上得了“廳堂”下得了“廚房”只有少數大神能做到,加上機器語言純用“0”和“1”序列組成,既對視力是一種摧殘,也是對編程趣味的扼殺。

於是,有一幫人開始琢磨了:能不能將計算機硬件從編程中分離出來,讓硬件知識小白也能編程?

最先開竅的是藍色巨人IBM,它在其System/360計算機中引入了ISA(Instruction Set Architecture)概念,將編程所需要了解的硬件信息從硬件中抽象出來,這樣編程人員就可以面向ISA編程。由於ISA是用來描述編程時用到的抽象機器(不是具體的電腦CPU),包括了一套指令集和一些寄存器,因此,程序員只要知道ISA,不需要了解具體的硬件知識(每一兩年硬件都會換新),就可以編寫程序,在ISA相同的電腦上運行。

這樣一來,程序員不必瞭解過於專業的計算機硬件知識,不需要下得了廳堂,可以專心在“廚房”烹調程序大餐。

由此也可以看出,程序員很多都是不瞭解計算機硬件的,所以妹子們不要指望自己的程序員男朋友給你DIY電腦,或者電腦壞了,他能給你省下一筆修理費。他說不會修,那就是真的不會修。

極客漫畫《編程語言之戰》。


自從不用懂硬件也能編程的高級語言出現後,人類開始了編程上的放飛自我,經過數十年發展,高級編程語言已超過2500種。

但矛盾出現了,CPU能理解的機器語言還是那個機器語言,幾十年來沒有變化,怎麼辦?

其實,早在高級語言出現之前的彙編語言時代,聰明的計算機研發人員就開發出了專門的程序,用來將彙編語言和高級語言翻譯成機器語言,其過程相當於將英語名著翻譯成漢語著作。這種翻譯程序相當於人類中的翻譯家。

編譯器有兩種方法用於翻譯:編譯和解釋,相應的名稱是編譯器和解釋器。

兩者的區別是,編譯是在執行前把整個源程序(高級語言程序)翻譯成目標程序(機器語言程序),而解釋是一次只翻譯和執行源程序中的一行。

打個形象的比方,解釋器相當於發佈會的實時翻譯,演講的嘉賓說一句,實時翻譯馬上翻譯一句。編譯器則相當於著作翻譯家,整本翻譯完成後,再讓出版社印刷上市。

將高級語言翻譯成機器語言的過程。個人手繪比較粗糙,大家湊合看。


重點來了,從以上的內容可以看出,由於CPU不能直接理解用高級語言寫成的代碼,必須由翻譯程序翻譯成機器語言,因此翻譯程序可以極大地影響甚至決定處理器性能的發揮。如果沒有一個好的翻譯程序,那麼CPU的性能再強大,也好比茶壺裝的餃子,倒不出來。

正因為如此,谷歌在安卓4.4之後,拋棄了Dalvik虛擬機,改為ART,實際是將翻譯程序從解釋器切換到編譯器,發揮了芯片的性能,提高了程序運行效率。

現在,手機大廠包括華為、OPPO和vivo都開始重視編譯器開發,說到底就是為了發揮芯片性能,讓它不再成為倒不出餃子的茶壺。

最後總結一下,用翻譯程序把程序員編寫的程序翻譯成二進制代碼的機器語言後,CPU就能認識了,而且翻譯程序的優劣可以影響乃至決定CPU性能發揮。


魔鐵的世界


其實,CPU也不知道我們敲得代碼是什麼意思。想要讓一段代碼編程可執行的程序,需要進行一系列的操作。

關於CPU識別程序的問題,細講起來是比較麻煩的一件事情,我們來分步驟逐一解釋。

1.CPU的基本工作原理——數字電路

在具體將這個問題之前,我們先來了解一下半導體的特性。

顧名思義,半導體就是一種介於導體和絕緣體中間的物質,它具有以下特性。

比如上圖,如果電流是從A端流向C端,則電路通暢;反過來的話就不行了。大家可以把它理解一種單方向控制電流的設備。

電流只有兩種情況:開路和閉路,將開路規定為0,閉路規定為1,這也就是我們所熟知的二進制。

根據這種特性,設計者們開發出了“與”,“或”,“非”,“異或”四種情況:

  • 與門:只有同時具備條件A和條件B時,才能得出結果1,當其中任意一個條件為0時,結果為0。

1+1=1; 1+0=0; 0+1=0; 0+0=0

  • 或門:只有條件A或條件B都為0時,才能得出結果0;當其中任意條件為1時,結果為1;

1+1=1; 1+0=1; 0+1=1; 0+0=0

  • 非門:就是相反的意思,條件A的反為B,條件B的反為A;

輸入x 輸出y

0 1

1 0

  • 異或門:當兩個條件取值相異(0和1)時,結果為1;反之為0

1⊕1=0;

1⊕0=1;

0⊕0=0;

根據這幾種門電路,還衍生出了一些電路,比如與非門,或非門等等。但基本的電路狀還是不會變的。這些門電路構成了CPU的基本工作原理——數字電路。

無論是數據的計算,還是指令的調度,CPU都是要通過運算來實現的。門電路的目的就是為了通過控制電流的狀態,來實現計算的原理。當然了CPU上的電路是非常複雜的,如何將由門電路構造成的加法器,乘法器之類集成到一塊指甲蓋大小的電路板上絕非易事,這也是為什麼芯片技術被稱為最難突破的尖端技術的主要原因之一。

在簡單瞭解CPU的工作原理後,就是關於高級語言和機器語言的轉換問題了

機械語言和高級語言

早期的計算機編程是一件非常痛苦的事情,只要涉及到需要位移量的運算時,例如乘法運算,就要做大量的插線工作。也許一個幾分鐘就能算完的程式,插拔線路就得花上半個小時,還不能插錯,否則就白忙活了。所以當時做這些工作的都是一些靚麗的摩登女郎,穿著漂亮的制服以緩解工作人員的壓力……

隨著計算量不斷地增大,這種插拔的方式已經滿足不了實際需求。,人們開始考慮:能不能設計一種語言來更高效的設計程序呢?由此,高級語言誕生了。

高級語言:一種接近於人類自然語言的表達方式,通過一些較為直觀的單詞,符號來表示低級語言。從而使編程變得明瞭易學,可讀性強。

同時,高級語言分為面向過程和麵向對象兩類。前者在同一個功能每實現一次,都得重新編寫一次代碼,所以代碼的重複利用率比較差;後者面向由於引入了類的概念,只要只要編寫一次代碼,後面便可以通過調用類的方式多次使用,大大提升了效率。所以java能成為最受歡迎的編程語言不是沒有道理的。

機器語言:計算機最原始的語言,全部由0和1構成的數字串構成,也是cpu唯一可以識別的語言。

另外,還有一種彙編語言,很多人存在一個誤區,覺得彙編語言就是機器語言,其實不然,CPU還是不知道彙編語言是個什麼東西。彙編語言本質上還是一種計算機低級語言,通過彙編語言我們可以瞭解CPU 到底幹了些什麼,以及代碼的運行步驟。

如何將高級語言轉換成計算機可以識別的機器語言呢?這時候就需要編譯器的發揮作用了:

簡而言之,編譯器就像是一箇中轉平臺,就是將程序員使用的高級語言翻譯為計算機可以識別運行的機器語言。其主要工作流程可以具象為:源代碼 (source code) → 預處理器 (preprocessor) → 編譯器 (compiler) → 目標代碼 (object code) → 鏈接器(Linker) → 可執行程序 (executables),也就是我們最終使用的後綴名為.exe這樣的程序。

最後說個題外話,編譯器對於程序的所起的影響可謂舉足輕重,甚至可能影響到CPU的執行效率。所以現在廠家除了絞盡腦汁的提升CPU性能外,也將目光投向了編譯器,編譯器極有可能在未來成為新的熱門導向。



愛思考的奧特曼


如果你是一個程序員,你寫過很多代碼,那麼現在要你寫一段程序,計算50.00*0.1的值。

你也許會這樣寫:

代碼你很快寫完了,如果沒有和其他人交流,可能只是你自己看了,而抱歉的是CPU也不認識你寫的是啥。

CPU並不認識你寫的程序

CPU不知道也不管你是用什麼語言寫的代碼,那是給人閱讀的,不是給CPU閱讀的,CPU只懂得編譯過的二進制指令,也就是一大串的0和1,還必須按照商家設計好的指令體系編制的指令序列才行。至於你寫的那些牛B的代碼,CPU並不買賬,它好不好用在於編譯器或解釋器把這些人類代碼翻譯為機器碼有多高明。

那CPU是怎麼去執行我們的程序呢?

這就是編譯器存在的原因了,編譯器將我們寫的程序編譯成可供CPU執行的二進制代碼,並且分配指令和內存的地址等這類複雜的工作。

程序大體的執行流程

一個程序的執行流程總體上可以分為3個步驟:磁盤->RAM(內存)->CPU

即程序從磁盤拷貝到內存中,CPU從內存中取指令,然後解碼,之後執行,最後將執行結果寫回內存。

CPU又是如何執行指令的呢?

硬件產商約定好了一套指令體系,不管什麼編程語言都通過某種方式把代碼編譯為CPU能懂的二進制指令指揮CPU工作。

比如:有一串指令過來了,如果是以1開頭,則表示做什麼,比如做加法,那麼後面接著會發過來兩個數,CPU做加法後把結果存入既定的寄存器,程序會有後續的指令去這個寄存器提取結果,放入指定的內存中。CPU就是按照這樣的約定解析傳入的一連串的二進制數據,並一一的去執行。這就好比航海的船通過約定的燈語(燈的有規律亮、滅)來相互通信的道理是一樣的。

總結

所以說,CPU不是認識代碼,而是記住代碼,數據總線送過來一個指令,是什麼要如何去執行,已經固化在了CPU裡了。如何執行和固化?是通過複雜的組合,以門、非門、與非門這三種複雜的組合,實現了複雜的邏輯關係。

以上是我個人的一些經驗和總結,希望可以幫助到大家,如果有不同意見可以評論區留言一起討論。


匯聚魔杖


什麼是代碼?代者,替換也。

假如你設計一個數字電路,包括一個加法器和一個乘法器。

你希望根據需要,有時對輸入數據做加法,有時對輸入做乘法,該怎樣做呢?

顯而易見的方法是手工控制加法器和乘法器的使能端,每次只讓一個電路工作。那麼當兩個使能端為01,就是加法器工作,是10,就是乘法器工作。

然後為了讓電路根據要求的順序做加法和乘法,你把一系列01、10存儲起來,當你要做加法,加法,乘法,加法時,存儲的就是01011001。你增加了一個時序電路,每次讀出兩個位,把高低電平加在兩個使能端上,替代你的手工接線。01和10這兩個數碼能控制電路的行為,起名叫機器碼。

然而這樣二進制的東西並不好記憶。於是你給01起了個名字,叫add,10起名叫mul。你的這組運算就記為add,add,mul,add。

add,mul這種助記符,就叫代碼,具體說是彙編代碼;你會找一個悲催的助手,幫你把代碼替換成01,10這種機械碼。

由代碼翻譯成機器碼的過程,後來也由機器來做,這種機器(軟件)就叫編譯器。

因此所謂cpu認識代碼,是一種擬人化的修辭,偏文藝了。cpu只是一種根據高低電平輸入,產生特定的高低電平輸出的機器。代碼不過是助記符。

後來你覺得add,add,add,add,add這類寫法太煩,於是發明了五連加,7連乘之類的寫法——高級語言代碼誕生了。


味冷


你看看海上船隻之間通過打燈光溝通是怎樣的,CPU執行代碼也是那個原理。

關鍵是約定一套信號協議。CPU只按傳入的二進制代碼執行指令,商家約定好了一套指令體系,不管什麼編程語言都通過某種方式把代碼編譯為CPU能懂的二進制指令指揮CPU工作。協議跟人與人的交流一樣,是有規矩的。舉個例子,發出一串指令,如果是以1開頭,則表示做什麼,比如做加法,那麼後面接著會發過來兩個數,CPU做加法後把結果存入特定的寄存器,程序會有後續指令去這個寄存器提取結果,放入指定的內存中,CPU按照這樣的約定解析傳入的一連串二進制數據,並一一執行。CPU能直接做什麼,根據這套指令體系來,不能直接做的,程序員負責編寫完整解決方案讓CPU能做出來,這就叫編程,整個指令序列叫程序。

CPU不認識你什麼語言代碼,那是給人閱讀的,不是給計算機閱讀的,計算機只懂編譯過的二進制指令,還必須是按照商家設計好的指令體系編制的指令序列才行。沒有什麼編程語言是高大上的,它好不好用,在於編譯器或解釋器把這些人類代碼翻譯為機器碼有多高明,守恆律在這方面仍然起作用,你寫的高級語言代碼越少,翻譯給機器執行的指令實際上越多。C入門最基礎的hello world程序,不要以為寫的很短就很得意,這程序編譯後的二進制機器碼有5K,printf()函數的源代碼有多長,可以自己去看看,但實際上你輸出一個字符串用不著完整的printf()功能,這函數其實一個低效的解釋型程序。


TonyDeng


高級語言通過編輯器轉為彙編代碼,程序運行時由另一段程序(操作系統)加載到內存中, 內存與cpu通過地址線、控制線、數據線與內存連接。cpu通過叫做IP寄存器(寄存器有很多種,可以把寄存器看做一個速度很快的內存)的硬件讀取到下一條指令在內存中的地址然後把這個地址信號通過控制線發送給內存控制器,內存控制器取出相應地址的數據,通過數據線發送給cpu,這就取到了一條機器指令。 cpu將這個機器指令分成兩段: 一段是操作數 ,一段是操作碼,cpu通過操作數操作碼來控制寄存器訪問內存、訪問寄存器、啟動cpu內置的計算相關的電路(ALU)最後更新ip寄存器的內容, 再通過ip寄存器發出的信號找到下一條指令並且執行, 週而復始直到程序遇到特殊的指令來結束這個程序。


A騎著白馬的悟空


Cpu說,我只會 洗衣服,做飯,掃地 三件事,你只要告訴我要做哪件事,別的我一個字都不聽。這三件事就是CPU的指令集。

所以,CPU根本不認識代碼,只是代碼按照CPU給定的指令集去調用而已


alex136442470


準確的說,CPU不是認識代碼,而是記住代碼,數據總線送過來一個指令,是什麼如何執行,已經固化在CPU裡了,如何執行和固化?是通過複雜的組合,以門,非門,與非門這三種複雜的組合,實現了複雜的邏輯關係。


繁華落盡任浮沉


CPU不認識代碼,只認識有電(1)和沒電(0),代碼經過轉換最終變成開關信號控制三極管的通與斷!


分享到:


相關文章: