1、編譯與鏈接的區別是什么?
在多道程序環境中,想將用戶源代碼變成一個可在內存中執行的程序,通常可分為三步:編譯、鏈接和載入。
編譯
將預處理生成的文件,通過詞法分析、語法分析、語義分析以及優化后編譯成若干目標模塊。可以理解為將高級語言翻譯成二進制代碼的機器語言。windows下編譯成.obj文件,Linux下編譯成.o文件。鏈接
由鏈接程序,將編譯后形成的一組目標模塊以及它們所需要的庫函數鏈接在一起,形成一個完整的載入模型。鏈接主要解決相互引用的問題,分為地址和空間分配,符號解析和重定位幾個步驟。在編譯階段生成目標文件時,會暫時擱置那些外部引用,而這些外部引用就是在鏈接時確定的。鏈接器在鏈接時,會根據符號名稱去相應模塊中尋找對應符號。帶符號確定后,鏈接器會重寫之前未確定的符號地址,這個過程稱為重定位。鏈接一般分為:靜態鏈接,載入時動態鏈接和運行時動態鏈接三種。載入
由載入程序將載入模塊載入內存。
編譯和鏈接是為將用戶程序從硬盤上調入內存并將其轉化為可執行程序服務的。編譯時,編譯器需要的是語法正確,函數與變量的聲明正確。一般而言,每個源文件都應該對應于一個中間目標文件。鏈接時,主要是鏈接函數和全局變量,所以可以采用這些中間目標文件來鏈接應用程序。鏈接就是目標文件相互鏈接自己需要的函數和全局變量,而函數可能源于其他目標文件或庫文件。
2、編譯型語言與解釋型語言的區別是什么?
編譯型語言
編譯型語言是指應用源程序執行之前,就將程序源代碼“翻譯”成目標代碼(“機器語言”)保存在另一個文件中,因此目標程序可以脫離語言環境獨立執行多次,使用比較方便,效率較高。但應用程序一旦需要修改,必須先修改源代碼,只有目標文件沒有源代碼,則修改很困難。大多數軟件產品都是應目標程序形式發布給用戶,不僅可以直接運行,還可以使他人難以盜用其中的技術。C/C++/Fortran/Visual Foxpro/Psacal/Delphi等都是編譯型語言。解釋型語言
解釋型語言相對于編譯型語言存在的,源代碼不是直接翻譯成機器語言,而是先翻譯成中間代碼,再由解釋器對中間代碼進行解釋運行。解釋程序的任務是逐一將源程序的語句解釋成可以執行的機器指令,不需要編譯鏈接成目標代碼后再執行,當語句出現語法錯誤,解釋器可以立刻引起程序員的注意,程序員可以在開發階段進行校正。每條語句只有在執行時,才被翻譯,解釋程序每執行一次,就翻譯一次,因此效率低下且依賴解釋器,但是其跨平臺性好。Python/JavaScript / Perl /Shell等都是解釋型語言。
Java是一類特殊的編程語言,其程序也需要編譯,但是卻沒有直接編譯稱為機器語言,而編譯為字節碼,然后在Java虛擬機上一解釋方式執行字節碼。
3、如何判斷一段程序是由C編譯的還是由C++編譯的?
如果編譯器在編譯cpp文件,那么自定義宏_cpluslus
就會被定義,如果是一個c文件被編譯,那么_STDC_
就會被定義。_STDC_
是預定義宏,當它被定義后,編譯器會按照ANSIC的標準來編譯C語言程序。
C與C++編譯方式不同。編寫C/C++的兼容代碼,需要如下格式:
#ifdef _cplusplus
extern "C"{
#endif
//code
#ifdef _cplusplus
};
#endif
4、extern “C”的作用是什么?
C++是一種面向對象語言,支持函數重載,而C語言是面向過程語言,不支持函數重載,所以函數在被C++編譯后再庫中的名字與C語言不同。如果聲明一個float f(int a, char b)
,C語言一般使用類似_f
的內部名,而C++則將參數連在其中,內部名類似_f_int_char
。因此,鏈接器無法解釋C++程序對C語言函數f的調用。
C++提供了C語言替代連接說明符號extern "C"
來解決名字匹配問題,該語句用在函數前:extern "C" float f(int a, char b)
,其目的是告訴編譯器f()
是C連接的,不需要按照C++的方式轉換函數名,這樣就可以正確鏈接到f()
函數了。