1. 程式人生 > >程序的基本概念

程序的基本概念

腳本 描述 代碼 查表 指令 mac evel 操作系統 erp

第一章 程序的基本概念

  1. 程序和編程語言

程序是告訴計算機如何完成一個計算任務,這裏的計算可以是數學運算,比如解方程,也可以是符號運算,比如查找和替換文檔中的某個單詞。

從根本上說,計算機是由數字電路組成的運算機器,只能對數字做運算,程序之所以能做符號運算,是因為符號在計算機內部也是用數字表示的;

此外,程序還可以處理聲音和圖像,聲音和圖像在計算機內部必然也是用數字表示的,這些數字經過專門的硬件設備轉換成人可以聽到、看到的聲音和圖像。

程序是由一系列指令(Instruction)組成,指令是知識計算機做某種動作的命令,通常包括以下幾類:

輸入(Input):從鍵盤、文件或者其他設備 獲取數據;

輸出(Output):把數據顯示到屏幕或者存入一個文件,或者發送到其他設備;

基本運算:執行最基本的數學運算(加減乘除)和數據存儲;

測試和分支:測試某個條件,然後根據不同的測試結果執行不同的後續命令;

循環:重復執行一系列操作。

編寫程序可以說是這樣一個過程:把復雜的任務分解成子任務,把子任務再分解成更簡單的任務,層層分解,直到最後簡單的可以用以上指令來完成。

編程語言(Programming Language)分為低級語言(Low-level Language)和高級程序語言(High-level Language)。機器語言(Machine Language)和匯編語言(Assembly Language)屬於低級語言,直接用計算機指令編寫程序。而C、C++、Java、Python等屬於高級語言,用語句(Statement)編寫程序,語句是計算機指令的抽象表示。

編程語言

表達形式

C語言

a = b + 1;

匯編語言

mov 0x804a01c,%eax

add $0x1,%eax

mov %eax,0x804a018

機器語言

a1 1c a0 04 08

83 c0 01

a3 18 a0 04 08

匯編語言把機器語言中一組一組的數字用助記符(Mnemonic)表示,直接用這些助記符寫出匯編程序,然後讓匯編器(Assembler)去查表把助記符替換成數字,也就把匯編語言翻譯成了機器語言。

C語言的語句要翻譯成三條匯編或機器指令,這個過程稱為編譯(Compile),由編譯器(Compiler)來完成,顯然編譯器的功能比匯編器要復雜的多。

C語言是可移植的(Portable)或者稱為平臺無關的(Platform Independent)。平臺這個詞由很多解釋,可以指計算機體系結構(Architecture),也可以指操作系統(Operating System),也可以指兩者的組合。不同的計算機體系結構由不同的指令集(Instruction Set),可以識別的機器指令格式是不同的,直接用某種體系結構的匯編或機器指令寫出來的程序只能在這種體系結構的計算機上執行,然而各種體系結構的計算機都有各自的C編譯器,可以把C程序編譯成各種不同體系結構中的機器指令,這意味著C語言寫出來的程序只需稍加修改甚至不用修改就可以在不同的計算機上編譯運行。

各種高級語言都具有C語言的這些優點,所以絕大部分程序是用高級語言編寫的,只有和硬件關系密切的的少數程序(例如驅動程序)才會用到低級語言。

編譯執行的過程,首先你用文本編輯器寫一個C程序,譚厚保存成一個文件,例如program.c(通常C程序的文件名後綴是.c),這稱為源代碼(Source Code)或源文件,然後運行編譯器對他進行編譯,編譯的過程並不執行程序,而是把源代碼全部翻譯成機器指令,再加上一些描述信息,生成一個新的 文件,默認a.out,這稱為可執行文件,可執行文件可以被操作系統加載運行計算機執行該文件中由編譯器生成的指令。

技術分享圖片

解釋執行的過程,有些高級語言以解釋的方式(Interpret)執行,解釋執行的過程和C語言執行的過程很不一樣。例如編寫一個Shell腳本script.sh,用Shell程序/bin/sh解釋執行這個腳本:/bin/sh script.sh.這裏的/bin/sh稱為解釋器(Interpreter),它把腳本中的每一行命令解釋執行,而不需要生成包含機器指令的可執行文件再執行。

技術分享圖片

  1. 自然語言和形式語言

自然語言(Natural Language)就是人類講的語言,比如漢語、英語和法語。這類語言不是人為設計(雖然有人試圖加強一些規則)而是自然進化的。形式語言(Formal Languag)是為了特定應用而人為設計的語言。例如數學家用的數字和運算符號、化學家用的分子式等。編程語言也是一種形式語言,是專門設計用來表達計算過程的形式語言。

  1. 程序的調試

編程是一件復雜的工作,因為是人做的事情,所以難免經常出錯。有時候調試是一件非常復雜的工作,要求程序員概念明確、邏輯清晰、性格沈穩,還需要一點運氣。調試的技能我們在後續的學習中慢慢培養,但首先我們要區分清楚程序中的Bug分為哪幾類。

編譯時錯誤

編譯時只能翻譯語法正確的程序,否則將導致編譯失敗,無法生成可執行文件。對於自然語言來說,一點語法錯誤不是很嚴重的問題,因為我們仍然可以讀懂句子。而編譯器就沒那麽寬容了,只要有哪怕一個很小的語法錯誤,編譯器就會輸出一條錯誤提示信息然後罷工,你就得不到你想要的結果。雖然大部分情況下編譯器給出的錯誤提示信息就是你出錯的代碼行,但也有個別時候編譯器給出的錯誤提示信息幫助不大,甚至會誤導你。在開始學習編程的前幾周,你可能會花大量的事件來糾正語法錯誤。等到經驗更豐富之後你就會覺得,語法錯誤是最簡單最低級的錯誤嗎編譯器的錯誤提示也就那麽幾種,即使錯誤提示是有誤導的也能夠立刻找出真正的錯誤原因是什麽。相比下面兩種錯誤,語法錯誤解決起來要容易得多。

運行時錯誤

編譯器檢查不出這類錯誤,仍然可以生成可執行文件,但在運行時會出錯而導致程序崩潰。我們在調試或者學習C語言的很多語法時,要區分編譯時和運行時(Run-time)這兩個概念,有些事在編譯時做,有些事在運行做。

邏輯錯誤和語義錯誤

第三類錯誤是邏輯錯誤和語義錯誤。如果程序裏有邏輯錯誤,編譯和運行都會很順利,看上去也不產生任何錯誤信息,但是程序沒有幹它該幹的事情,而是幹了別的事情。當然不管怎麽樣,計算機只會按你寫的程序去做,問題在於你寫的程序不是你真正想要的,這意味著成簇的意思(即語義)是錯的。找到邏輯錯誤在哪裏需要十分清醒的頭腦,要通過觀察小恒旭的輸出回過頭來判斷它到底在做什麽。

  1. 第一個程序

例:Hello World

技術分享圖片

將這個程序保存成main.c,然後編譯執行:

技術分享圖片

gcc是Linux平臺的C編譯器,編譯後在當前目錄下生成可執行文件a.out,直接在命令行輸入這個可執行文件的路徑就可以執行它。如果不想把文件名叫,可以用gcc的-o參數自己指定文件名:

技術分享圖片

註意:main是一個特殊的名字,C程序總是從main裏面的第一條語句開始執行的,在這個程序中是指printf這條語句。

註釋用/* . . . */結構表示,編譯器會忽略從/*到*/的所有字符。

語句的末尾以;(Semicolon)結束,下一條語句return 0也是如此。

C語言中用{}括號(Brance或Curly Brance)把語法結構分成組,用若幹個(Blank)和Tab字符來縮進,漂亮的程序必須由整齊的縮進。

編譯器對於錯誤是毫不留情的,如果你的程序有一點拼寫錯誤,例如第一行寫成了stdoi.h,在編譯時會得到錯誤提示:

技術分享圖片

由些時候編譯器的提示信息不是error而是warning,例如上例中的printf(“Hello,World.\n”);改成printf(1);然後編譯運行:

技術分享圖片

這個警告信息是說類型不匹配,但勉強還能配得上。警告信息不是致命錯誤,編譯仍然可以繼續,如果整個編譯過程只有警告信息而沒有錯誤信息,仍然可以生成可執行文件。

出警告信息說明你寫的不夠規範,可能有Bug,雖然能編譯生成可執行文件,但程序的運行結果往往是不正確的,例如上面的程序運行時除了一個段錯誤,這屬於運行時錯誤。各種警告信息的嚴重程度不同,像上面這種警告幾乎一定表明程序中有Bug,而另外一些警告只表明程序寫的不夠規範,一般還是能正確運行的,**有些不重要的警告信息gcc默認是不提示的,但這些警告信息也有可能表明程序中有Bug。一個好的習慣是打開gcc的-Wall選項,也就是讓gcc提示所有的警告信息,不管是嚴重的還是不嚴重的,然後把這些問題從代碼中全部消滅。比如把上例中的printf(“Hello,World.\n”);改成printf(0);然後編譯運行:

技術分享圖片

編譯既不報錯也不報警告,一切正常,但是運行程序什麽也不打印。如果打開-Wall選項編譯就會報警告了:

技術分享圖片

如果printf中的0是你不小心寫上去的(例如錯誤地使用了編輯器的查找替換功能),這個警告就能幫助你發現錯誤。雖然通常省略-Wall選項,但是強烈建議你寫每一個編譯命令時,都加上-Wall選項。

程序的基本概念