第一章 程式語言導論
1-1程式語言基本概念
一、定義
程式 = 演算法+資料結構
是人類與電腦溝通的工具,能描述問題的演算法及其資料結構的概念。每種程式語言都有其特定的撰寫規則 (語法),只要依其規則撰寫,即可命令電腦完成某些特定的工作。
※圖靈機(Turing Machine):
[杜林機(Turing machine)] 2 | 94, 104
96交員晉高、104地三
1.又稱確定型圖靈機,是英國數學家艾倫·圖靈於1936年提出的一種抽象計算模型,其更抽象的意義為一種數學邏輯機,可以看作等價於任何有限邏輯數學過程的終極強大邏輯機器。
2.用機器來模擬人們用紙筆進行數學運算的過程,這樣的過程看作下列兩種簡單的動作:
(1)在紙上寫上或擦除某個符號。
(2)把注意力從紙的一個位置移動到另一個位置。
而在每個階段,人要決定下一步的動作,依賴於(1)此人當前所關注的紙上某個位置的符號和(2)此人當前思維的狀態。
3.使用一個無限長的磁帶當作記憶體,磁帶頭有讀與寫的功能,而且可以在磁帶上左右移動。
4.Turing Machine工作的情況就好像無法記得那麼長的資料,但是可以前後瀏覽,作記號並且比對。
※參考資料:
1.http://nthucad.cs.nthu.edu.tw/~yyliu/personal/nou/05ct/chp08.pdf
2.https://zh.wikipedia.org/wiki/%E5%9B%BE%E7%81%B5%E6%9C%BA
二、程式語言的分類
[程式語言分類] 3 | 93,103,104
93專檢、103檢三、104高三
(一)第一代程式語言-機器語言(machine language)
1.是由0與1組成的二進位碼所構成,不同類型的計算機擁有不同的指令群,對應的二進位碼亦不相同,因此是一種與機器相關的語言。
2.撰寫及維護都極為困難,例如麥金塔電腦與 IBM 個人電腦的機器語言不相容。
(二)第二代程式語言-組合語言(assembly language)
1.又稱為低階語言 (low-level language)。將每一條機器語言指令用一個助記憶符號 (memonic symbol) 來取代。
2.組合語言指令與機器語言指令具有一對一的對應關係,因此屬於與機器相關的語言。
(三)第三代程式語言-高階語言(high-level language):如何做(how) / 師傅
1.又稱為程序導向語言 (procedure oriented language),告訴電腦如何做。
2.與機器無關,具有移植性,不須要因為電腦設備的不同而修改大量程式指令。
3.例如 Pascal、C、C++、Basic、Fortran 與 Cobol。
(四)第四代程式語言-超高階語言(very high level language):做什麼(what) / 老闆
1.通常稱為 4GL (fourth generation language)。是問題導向語言 (problem oriented language) 或非程序導向語言 (non-procedure language),告訴電腦做什麼。
2.例如 SQL (Structured Query Language)。
(五)第五代程式語言-自然語言(nature language)
1.利用人工智慧技術,使其接近人類使用的自然語言 (如英語),讓電腦讀懂人類的語言。
2.目前人工智慧語言仍處於發展中的階段,現今開發的產品則多是以 Lisp 或 Prolog 語言為基礎,專為特定領域設計的知識庫系統 (如醫療、財經)。
※參考資料:
http://zh.wikipedia.org/wiki/%E8%87%AA%E7%84%B6%E8%AF%AD%E8%A8%80%E5%A4%84%E7%90%86
三、為何要學習程式語言
增進對所使用程式語言的了解、可以改進程式的架構、有助於選擇合適的程式語言、比較容易學習新的程式語言、較容易設計出一種新的程式語言。
四、電腦的應用領域及相關的程式語言
(一)科學應用:Fortran。
(二)商業應用:COBOL。
(三)人工智慧:LISP、Prolog。
(四)系統程式:發展 UNIX 所用的 C 語言。
(五)超高階語言
UNIX 上面的各種腳本語言 (scripting languages),例如 shell、ksh、awk、perl。
(六)特殊目的語言(問題導向語言)
例如用於產生商業報表的 RPG (Report Program Generator)。
※參考資料:http://en.wikibooks.org/wiki/Fortran/Fortran_examples
93年專門職業及技術人員檢覈程式語言
四、我們通常將程式語言分為五代。 (一)請問第一代程式語言所指為何?(5分) (二)第二代程式語言一般指的是「高階語言」,又稱為「程序導向語言」,請說明程序導向語言解決問題的方式為何?(5分) (三)第四代程式語言一般指的是「問題導向語言」(problem oriented language),例如 SQL,請說明 SQL 解決問題的方式為何?(5分) (四)第五代程式語言一般指的是「自然語言」(nature language),又稱為「知識庫語言」,請說明此類語言解決問題的方式為何?(5分) |
答:
略
103年檢察事務官三等程式語言
一、何謂程式語言 (programming language)?又有那些分類?(17分) |
答:
略
1-2 高階程式語言
一、高階語言的優點
(一)學習容易,學習時間較短
(二)生產力較高,對於人力及管理的需求較少
(三)與機器無關
(四)程式的除錯較容易
(五)編寫較大的應用程式時,不至因瑣碎的程式細節而影響設計的進行
(六)高階語言的結構本身就具有卓越的文件說明能力
二、高階語言的實作
[編譯(compilation)] 20 | 82,86,91,94(2),95(3),96,97(2),98(2),99,100,104,107(2),108,109
82地三、86高三、91地三、94高三(2)、95身三、95港員晉高、95地三、96地三、97高三、97地三、98關薦、98檢三、99高三、100關四、104地三、107關四、107鐵高、108關三、109身三
(一)編譯程式(Compiler):程式編譯器
1.定義:是一種系統程式,將高階語言的原始碼轉換成「可執行檔」 (目的程式)。
2.作法:
原始程式→編譯 (高階語言轉成組合語言)→組譯 (組合語言轉成機器語言)→目的程式。
3.流程:
4.例如:C、C++、COBOL、Ada。
※參考資料:
1.http://digital.cs.usu.edu/~cdyreson/teaching/languages/142/lectures/printintroduction.htm
2.Sebesta-Concepts of Programming Languages,10th p.25
※編譯器的六大階段:
※參考資料:陳鍾誠-系統程式-第8章編譯器.ppt
※語彙分析(Lexical Analysis):詞彙分析 / 詞法分析
1.定義:
將敘述句拆成組成語法的基本單元,例如保留字、關鍵字、識別字、運算子等。
2.範例:
sum = sum+i
詞彙(Token) |
sun |
= |
su, |
+ |
i |
詞類標記(Type) |
id |
= |
id |
+ |
id |
※參考資料:陳鍾誠-系統程式-第8章編譯器.ppt
※語法分析(Syntax Analysis):
1.將程式符號轉換成階層式的語法樹 (Syntax Tree) 符號。
2.在語法樹中,階層最高的節點 (Node) 為 assign 的符號,其餘的節點為其他的運算元符號,而葉子 (Leaf) 就都是變數的標記 (Token)。
※語意分析(Semantic Analysis):
1.定義:
藉由語法樹來分析程式的邏輯與語法是否符合規定。主要是為語法樹加註節點的資料型態,並且檢查資料型態是否相容,然後輸出語意樹。
2.範例:
語意分析器將會發現到 a 與 b 是無法相乘的,因而輸出錯誤訊息。
C語言程式 |
語義分析的結果 |
int a = 5, c; char b[10]; c = a*b; |
a, c 是整數 b 是字元陣列 c (錯誤?) = a (整數) * b (字元陣列) |
※參考資料:陳鍾誠-系統程式-第8章編譯器.ppt
※中間碼產生:語意樹→中間碼
1.使用時機:語意樹建立完成後,就可以將語意樹中的每個節點展開為中間碼。
2.方法:
利用遞迴的方式,從根節點開始,遞迴展開每個子節點,直到所有節點的中間碼都產生完畢為止。
3.範例:
C語言程式 |
中間碼 |
說明 |
sum = 0; for(i = 1; i <= 10; i++) { sum = sum+i; } return sum; |
= 0 sum = 1 i FOR0: CMP i 10 J > _FOR0 + sum i T0 = T0 sum + i 1 i J FOR0 _FOR0: RET sum |
設定 sum 為0 設定 i 為1 for 迴圈的起始點 i > = < 10 ? if(i > 10) goto FOR1 T0 = sum+i sum = T0 i = i+1
傳回 sum |
※參考資料:陳鍾誠-系統程式-第8章編譯器.ppt
※指定述句的翻譯:
註:
01 LDF R2, id3
02 MULF R2, R2, #60.0
03 LDF R1, id2
04 ADDF R1, R1, R2
05 STF id1, R1
1.每個指令的第一個運算元指定了目的位址。各個指令中的 F 告知所它處理的是浮點數。
2.第一個指令:把程式碼把位址 id3 中的內容載入暫存器 R2。
3.第二個指令:把將其與浮點常數60.0相乘,“#”表示60.0應該視為直接常數。
4.第三個指令:把 id2 移到暫存器 R1。
5.第四個指令:把前面計算並存放在 R2 的值加到 R1。
6.第五個指令:把暫存器 R1 的值存放到 id1 的位址。
※參考資料:趙建華-編譯系統設計.pdf
※程式編譯器:
先用編譯再組譯。
※編譯(Compiler):
將高階語言轉成組合語言。
※組譯(Assembling):
將組合語言轉成機器語言。
※編譯器的步驟:
步驟 |
內容 |
1.詞彙分析(Lexical Analysis) |
將整個程式分成一個一個的基本詞彙 (token) |
2.語法分析(Parsing或Syntax Analysis) |
剖析器利用語法規則進行比對,建立語法剖析樹 |
3.語意分析(Semantic Analysis) |
為剖析樹加註節點型態,並檢查型態相容性,輸出語意樹 |
4.中間碼產生(Pcode Generator) |
將語意樹轉換成中間碼 |
5.最佳化(Optimization) |
考慮暫存器配置問題,降低指令數量,增加效率 |
6.組合語言產生(Assembly Code Generator) |
將中間碼轉換為組合語言輸出 |
7.編譯組譯(Compilation Assembly) |
將中間碼碼產生的組合語言轉換成機器語言及載入程式所需的資訊 |
※參考資料:
http://www2.nuu.edu.tw/~elearning/nuuopencourse/93open/93004/html/contents.htm
※程式編譯器的過程:
1.Dev-C++ 主要工作為預先處理 (Preprocess)、編譯 (Compile) 和組譯(Assemble)。
2.預先處理是做一些在編譯前要做的工作,之後就進行編譯。
3.在編譯過程中,會檢查程式有沒有錯誤,而錯誤主要有語法錯誤 (Syntax Error) 和語意錯誤 (Semantic Error) 兩類。
4.如果有上述錯誤,編譯器會通知,而且停止編譯過程,這時候要修正程式內的錯誤,修改後重新開始編譯。
5.當沒有任何錯誤後,編譯器會把程式內每個句子轉成更低階的方式,一般是轉成組合語言 (Assembly)。
6.轉成組合語言後,組譯時 (通常編譯器都內置了組譯器) 就會把每個組合語言句子轉成機械語言 (Machine Code),也稱為目的碼 (Object Code),產生另一個檔案 “file.obj”。
7.最後到了連結 (Link) 過程,就會把程式、有關的程式和程式庫所產生出來的 *.lib,轉成可以在電腦上執行的方式,產生另一個檔 “file.exe”,這個檔案就可以執行了。
※參考資料:http://www2.lssh.tp.edu.tw/~hlf/class-1/lang-c/compile.htm
※語法錯誤(Syntax Error):
1.定義:
(1)程式的語法有誤,編譯器或解譯器在詞法分析時無法將其轉換為適當的程式語言。
(2)在編譯語言中,語法錯誤一定只在編譯期時出現,編譯器要所有的語法都正確,才能正確編譯。不過直譯語言中的語法錯誤可能要到執行期才會出現,而且不一定容易區分語法錯誤及語意錯誤。
2.範例:
在Java語言中,以下的程式是正確的:
System.out.println("Hello World");
以下的程式不正確:
System.out.println(Hello World);
第二個程式理論上要顯示的是叫作 Hello World 的變數,而不是 Hello World這個字,而且 Java 語言的變數名稱中不可有空白,因此會出現語法錯誤。
※參考資料:
https://zh.wikipedia.org/wiki/%E8%AF%AD%E6%B3%95%E9%94%99%E8%AF%AF
※語意錯誤(Semantic Error):邏輯錯誤(Logic error)
1.定義:
(1)是程式錯誤的一種,這種錯誤會導致程式執行出錯,但是不至於崩潰。
(2)會產生意外的輸出或結果,但是並不一定會立即被發現。
(3)與語法錯誤的程式不同的是,語意錯誤的程式從語法上來說是正確的一段程式,但是執行結果與預期不符。
2.範例:
int average(int a, int b) { return a + b / 2; /* 應該是 (a+ b) / 2 */ } |
程式碼中缺少了一對括號,因此程式雖然能夠通過編譯並執行,但是由於運算子優先級 (先乘除,後加減) 的緣故,運算結果並不正確。
3.可能原因:
語句公式寫錯、演算法錯誤、選擇錯誤的演算法、類型轉換錯誤、變數的有效範圍錯誤、遺漏的程式碼區段 (code segment)、對問題或需求的理解有誤等等。
4.解決方式:將程式中的變數輸出到檔案或列印到螢幕,以定位錯誤所在。
※參考資料:
https://zh.wikipedia.org/wiki/%E9%80%BB%E8%BE%91%E9%94%99%E8%AF%AF_(%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1)
※目的碼(object code):
1.指電腦科學中編譯器或組譯器處理原始碼後所生成的代碼,它一般由機器碼或接近於機器語言的代碼組成。
2.目的檔 (object file) 即存放目的碼的電腦檔案,常被稱作二進位檔案。
3.目的檔包含著機器碼 (可以直接被電腦中央處理器執行) 以及代碼在執行時使用的資料,例如重定位資訊、用於連結或偵錯的程式符號 (變數和函式名稱),此外還包括其他偵錯資訊。
4.目的檔是從原始碼檔案產生程式檔案這一過程的中間產物,連結器正是通過把目的檔連結在一起來生成可執行檔或庫檔案。
5.目的檔中唯一的要素是機器碼,例如用於嵌入式系統的目的檔可能僅僅含有機器碼。
※參考資料:
https://zh.wikipedia.org/wiki/%E7%9B%AE%E6%A0%87%E4%BB%A3%E7%A0%81
※預先處理(Preprocess):
1.#define巨集的宣告與使用:
巨集指令 #define 宣告的格式如下
#define macroname string
假設有一 C 程式檔 file.c 其內容為:
#define MAXSIZE 100
main( ) {
int A[MAXSIZE];
}
於編譯時經過前置處理後,該程式變成
main( ) {
int A[100];
}
其中所有的 #define 指令都不見了,MAXSIZE 也都變成了100。
2.#include的使用:
(1)C 程式的設計,不僅可以用模組化的方式,以函數來表現,亦可將程式碼依其不同的目的與功能,呈現在不同的檔案中。
(2)為了程式碼的一致性,例如常數、巨集指令和全域 (global) 變數宣告一些函數 (僅列出函數的標題 heading) 等,都放在一檔頭檔 .h,當然不見的是要以 .h 當作副檔名,不過,一般都是以 .h 來當作 include 檔的副檔名,再以指令 #include 方式將該檔 加入即可。指令 #include 的宣告方式如下:
#include <filename>
或
#include "filename"
經過編譯器前置處理後,含指令 #include 這行則由該檔 filename 來代替,如果 filename 是由 < > 所含,則編譯器會到 include 目錄下去找該檔或至預設的目錄去找。" " 常用來引用自定義的頭文件。
假設檔案 file1.h 的內容如下:
#define MAXSIZE 100
extern int size;
int f(int x);
假設檔案 file2.c 的內容如下:
#include "file1.h"
main( ) {
int A[MAXSIZE], i, sum;
for(i = 0; i < size; i++)
sum = sum+f(i);
}
假設 file1.h 與 file2.c 都在同一目錄,經過前置處理,file2.c 就先變成:
#define MAXSIZE 100
extern int size;
int f(int x);
main( ) {
int A[MAXSIZE], i, sum;
for(i = 0; i < size; i++)
sum = sum+f(i);
}
經過前置處理完成後,file2.c 就變成:
extern int size;
int f(int x);
main( ) {
int A[100], i, sum;
for(i = 0;i < size; i++)
sum = sum+f(x);
}
3.#if、#ifdef等的使用:
如果在一檔案欲 include 一檔頭檔 file1.h,又想避免在同一檔案宣告兩次相同的東西,例如:
檔案 file1.h 含 extern int size
檔案 file2.h 含 #include "file1.h"
檔案 file3.h 含 #include "file1.h"
檔案 file.c 含 #include "file2.h" 及 #include "file3.h"
則在檔案 file.c 內,變數 size 重複宣告了兩次而產生錯誤。
欲避免這種情況發生,每個 #include "file1.h" 指令,可以改變為如下指令:
#if !define(FILE1) // 如果沒有定義一個 file1.h 標頭檔,就執行底下所有操作
#define FILE1 "file1.h" // 定義一個巨集名稱 FILE1 為 file1.h 字串
#include FILE1// 在程序中包含頭文件
#endif // 結束
或是
#ifndef FILE1
#define FILE1 "file1.h"
#include FILE1
#endif
如果一個辨識名稱 X 沒有被 define 過,則 define(X) 的值為0,或者 ifndef X 為真值。當 file2.h 與 file3.h 都含上述指令,如此一來 file1.h 僅能一次被加入 file.c 而不致於產生衝突。
※參考資料:http://nknucc.nknu.edu.tw/~jwu/c/cpgch8.htm#third
※C語言前置處理器:
107鐵員
1.定義:
(1)負責處理編譯之前的準備工作,其主要的三個工作項目為:
a.#define 巨集及常數的宣告與使用 (定義巨集及常數)。
b.#include 的使用 (含入標頭檔)。
c.#if、#ifdef 等的使用 (條件式編譯)。
(2)是一種特殊的文字編輯器,語法和 C 語言完全不同,能處理常數、巨集及 include 檔。
(3)可以條件式編譯,例如要在測試時將除錯用的程式碼放進來,然後在正式發行時予以刪除。如下:
#include < stdio.h > #define value 99 void main(void) { #if value < 100 printf("value < 100"); #else printf("value >= 100"); #endif } |
2.原理:
(1)前置處理程式將原始檔中的 # 開頭的指令全部轉換為 C 指令。例如 #include <stdio.h> 將 stdio.h 內容展開。
(2)編譯程式將純 C 檔案轉為對應的機器語言 (目的檔案)。
(3)連結程式將所用到的 C 函數由函式庫連結到目的檔案後形成執行檔。
(4)執行檔 .exe 才是真正可執行的檔案。
※靜態連結(Static Linking):
106檢三
(一)定義
1.會在開發階段將程式所需要的函數、資源等全部加入程式的執行檔,執行檔的體積因此變大,所以靜態連結的執行檔往往需要較大的記憶體空間,當所用的函式庫越多時,執行檔也就越龐大。
2.例如在程式開發中,將各種目的模組 (.OBJ)、執行時期程式庫 (.LIB) 檔案,以及已編譯的資源 (.RES) 檔案連結在一起,以便建立 Windows 的 .EXE 檔案。
※參考資料:
1.http://monkeycoding.com/?p=876
2.http://www.twword.com/wiki/%E9%9D%9C%E6%85%8B%E9%80%A3%E7%B5%90
(二)靜態連結的方法
#pragma comment(lib, “test.lib”),靜態連結的時候,載入代碼就會把程式會用到的動態代碼或動態代碼的地址確定下來。
※參考資料:https://read01.com/OyM8Pn.html
(三)優點
1.由於靜態連結是把整個 Library 包進去執行檔,因此可以保證到不同機器環境下執行時,也不會因為少了這個函式庫導致無法執行檔案。
2.以二進位發布時不需要考慮在使用者的電腦上函式庫檔案是否存在及版本問題,可以避免 DLL 地獄 (DLL Hell) 等問題。
※參考資料:
1.http://monkeycoding.com/?p=876
2.https://zh.wikipedia.org/wiki/%E9%9D%99%E6%80%81%E5%BA%93
[註]
動態連結在 UNIX/Linux 與 Windows中卻有不同的稱呼,在 Windows 中直接稱為 DLLs (Dynamic Linking Libraries),其附檔名通常為 .dll,而在UNIX/Linux 中的動態連結函式庫則被稱為 Share Objects,其附檔名通常是 .so。
※參考資料:http://sp1.wikidot.com/linuxdynamiclinking
(四)缺點
1.檔案會比較大:
將程式所需要的函數、資源等全部加入程式的執行檔,所以檔案會比較大。
2.空間浪費:每個程式內部都會有 printf( )、scanf( ) 這些函式。
3.更新困難:
假如要更新某個 lib 檔,必須要對所有使用到這個 lib 檔的程式重新 Link,並且重新發佈給使用者。
※參考資料:
1.http://monkeycoding.com/?p=876
2.http://swaywang.blogspot.tw/2011/10/static-linking.html
(五)使用時機
共用檔少,而且函示庫稀有。
※參考資料:
http://turtlespeedlife.blogspot.com/2017/10/cstatic-library-dynamic-library.html
※動態連結(Dynamic Linking):
106檢三
(一)定義
1.動態連結的函式會在程式執行時才被載入,而不是直接編譯在執行檔中,這種作法讓系統更彈性的應用硬體資源,而且可以在不公開程式碼的情況下,分享給別人使用。
2.使用動態連結機制時,函式庫可以先不需要被連結進來,而是在需要的時候才透過動態連結器 (Dynamic Linker) 尋找並連結函式庫,這種方式可以不用載入全部的程式,因此可以節省記憶體。
3.當很多執行中的程式共用到函式庫時,動態連結所節省的記憶體數量就相當可觀。
※參考資料:
1.http://monkeycoding.com/?p=876
2.http://ccckmit.wikidot.com/lk:dynamiclinking
(二)動態連結的方法
1.把一些經常會共用的程式碼 (靜態連結的 OBJ 程式庫) 製作成 DLL 檔,當執行檔呼叫到 DLL 檔內的函式時,Windows 作業系統會把 DLL 檔載入記憶體內,DLL 檔本身的結構就是可執行檔,當程式有需求時,函式才進行連結。
2.在需要的時候才載入動態函式庫,並且進行連結 (linking) 與重新定位 (relocation) 的動作,然後再執行該函式庫中的函數。
※參考資料:
1.http://monkeycoding.com/?p=876
2.http://ccckmit.wikidot.com/lk:dynamiclinking
(三)優點
1.節省記憶體:可以不用載入全部的程式,因此可以節省記憶體。
2.可以單獨被編譯、組譯與連結:
因為動態連結函式庫 (Dynamic Linking Libraries, DLLs) 可以單獨被編譯、組譯與連結,所以可以節省編譯、組譯、連結所花費的時間。
3.執行檔較小:
動態連結是在程式開始執行時才載入的,所以執行檔較小,而且更新程式庫無需重新編譯其他程式。
4.升級與修改較為容易:
當 DLL 的函式變更時,只要函式的引數和回傳值沒有改變,使用這些函式的應用程式就不需要重新編譯或重新連結。
5.結合多種程式語言的程式碼:
當需要呼叫其他語言所製作的函式時,可以利用 DLL 來達成。例如使用VB 需要呼叫一些 C 語言的函式,可以先將 C 語言的部份做成 DLL 檔,再把呼叫 DLL 的程式碼寫在 VB 裡面,這樣就可以將C語言的程式納進 VB 的程式中。
※參考資料:
1.http://monkeycoding.com/?p=876
2.http://pws.niu.edu.tw/~ttlee/sp.100.2/dll/
3.http://ccckmit.wikidot.com/lk:dynamiclinking
(四)缺點
1.效能差:
因為每個呼叫都會有系統開銷,執行時連結要慢得多,對應用的效能有負面影響。
2.DLL地獄(DLL Hell):
可執行程式依賴分別儲存的庫檔案才能正確執行。如果庫檔案被刪除、移動、重新命名或者被替換為不相容的版本,那麼可執行程式就可能工作不正常。
※參考資料:
https://zh.wikipedia.org/wiki/%E5%87%BD%E5%BC%8F%E5%BA%AB
(五)使用時機
共用檔多,而且函示庫常見。
※參考資料:
http://turtlespeedlife.blogspot.com/2017/10/cstatic-library-dynamic-library.html
107年鐵路特考高員三級程式語言
三、在 Unix/Linux 的系統裡,libfoo.a 與 libfoo.so 之類的程式庫 (libraries) 有何不同?並依生成方式、使用方式、使用時機、對系統的影響等面向說明。(20分) |
答:
.a 為靜態函式庫,可以是一個或多個 .o 合在一起,用於靜態連結;.so 為動態函式庫,類似 Windows 的 DLL (Dynamic-link library) 檔。
※參考資料:
http://lionrex.pixnet.net/blog/post/117288156-%5Blinux%5D-.a---.so---.la-%E5%87%BD%E5%BC%8F%E5%BA%AB%E7%9A%84%E5%B7%AE%E7%95%B0
(一)生成方式
1.libfoo.a:
(1)先產生object file:
gcc -c test1.c test2.c
(2)再用ar,就可以產生靜態函式庫libfoo.a:
$ ar -r libfoo.a test1.o test2.o
2.libfoo.so:
(1)建立動態函式庫libfoo.so:
gcc -fPIC -shared -o libfoo.so max.c
得到 libfoo.so
上述過程分為編譯和鏈結兩步,-fPIC 是編譯選項,PIC 是 Position Independent Code 的縮寫,表示要生成位置無關的代碼,這是動態庫需要的特性;-shared 是鏈結選項,告訴 gcc 生成動態庫而不是可執行文件。上述的一行命令等同於:
gcc -c -fPIC max.c gcc -shared -o libfoo.so max.o
※參考資料:
1.http://lionrex.pixnet.net/blog/post/117288156-%5Blinux%5D-.a---.so---.la-%E5%87%BD%E5%BC%8F%E5%BA%AB%E7%9A%84%E5%B7%AE%E7%95%B0
2.https://www.cnblogs.com/jiqingwu/p/linux_dynamic_lib_create.html
3.http://terrycslife.blogspot.com/2010/07/so.html
(二)使用方式
1.libfoo.a:
產生靜態連結的執行檔:
gcc -o main main.c libfoo.a
2.libfoo.so:
(1)編寫原始檔案。
(2)將一個或幾個原始檔案編譯鏈結,生成共享庫 (Shared Library)。
(3)通過 - L <path> -lxxx 的 gcc 選項鏈結生成的 libfoo.so。
(4)把 libfoo.so 放入共享庫的標準路徑,或指定 LD_LIBRARY_PATH,才能運行鏈結 libxxx.so 的程序。
(5)產生動態連結的執行檔:
gcc -o main main.c libfoo.so
※參考資料:
1.https://www.ptt.cc/man/C_and_CPP/DBF2/D139/DA10/M.1212250886.A.DF4.html
2.https://www.cnblogs.com/jiqingwu/p/linux_dynamic_lib_create.html
3.http://www.programmer-club.com.tw/ShowSameTitleN/unix/1667.html
4.http://terrycslife.blogspot.com/2010/07/so.html
(三)使用時機
回答靜態連結及動態連結的使用時機。
(四)對系統的影響
回答靜態連結及動態連結的優缺點。
(二)直譯程式(Interpreter)
1.定義:
(1)是一種系統程式,按照高階語言所寫的原始程式執行時敘述的邏輯順序逐一將指令轉換為另一種語言並執行它。
(2)直譯器像是一位「中間人」,每次執行程式時都要先轉成另一種語言再作執行,因此直譯器的程式運行速度比較緩慢。
(3)不會一次把整個程式轉譯出來。每轉譯一行程式敘述就立刻執行,然後再轉譯下一行,再執行,如此不停地進行下去。
(4)可以使用語彙分析器 (lexical analyzer) 和語法分析器 (parser),然後轉譯產生出來的抽象語法樹 (abstract syntax tree)。
2.作法:原始程式→直譯程式 (原始程式轉成機器語言)→執行結果。
3.流程:
4.例如:JavaScript、Python、PHP、APL、SNOBOL、LISP。