❶ 用VS編譯和C++源文件的時候,源文件和庫文件是如何鏈接到源文件的具體細節
因為我是學習計算機軟體專業的,故可以給你講一下大概意思,我也不敢保證我講得都是正確的。個人講解僅供參考。這個是需要學習《計算機編譯原理》這門課程的。而且《計算機編譯原理》這門課程在軟體專業中幾乎是最抽象的、難於理解的。
首先關於 Visual Studio編譯器(或者是別的 C/C++編譯器)是如何將用戶親自編寫的源程序經過若干步驟之後,最終變成計算機可執行的二進制代碼程序?這裡面經過了如下步驟:
(1)、詞法分析/語法分析。也就是說當編譯器對用戶編寫的源程序進行編譯時,首先檢查你的詞法(或者是語法)是否正確,這是第一步(這里以 C 語言為例,假如將定義一個整型變數 n 的語句 int n ; 誤寫成了:intt n ; 屬於語法錯誤)。如果這一步都沒有通過編譯器的檢查的話,那麼絕對不會進入第二步。繼續返回編輯狀態進行語法檢查。這種錯誤是最容易檢查的。
(2)、語義分析。這類錯誤就要比(1)困難得多。這類錯誤舉例如下(這類錯誤編譯器只是會給出一個警告信息,但是編譯器是會放過這類錯誤的。故需要編程人員具有較豐富的編程經驗)
void main( )
{
int num ; /* 定義一個整型變數 num */
scanf("%d", &num ) ; /* 從鍵盤上輸入一個整數 */
if( num == 10 ) /* 在這個語句中,如果將邏輯判斷等於號 ==,誤寫為數值等於 =(即:if( num = 10 )),那麼該程序的執行結果始終輸出:Correct。因為該邏輯表達式 if( 10 ) 的真值始終為 1。 */
printf( "Correct !\n" ) ; /* 實際上程序的本意是:如果輸入的數值等於 10,則輸出:Correct ! */
else /* 如果輸入的數值不等於 10 的話,則輸出:Error ! */
printf( "Error !\n" ) ;
}
(3)、在(1)和(2)的基礎上進行中間代碼生成(例如:在linux 系統下面生成的 *.o 文件、或者是在 WINDOWS 系統下面生成的 *.obj 文件),這類文件還不是最終的可執行文件。
在此過程中,會應用到各種符號表,以便處理用戶程序中使用的各種常量、變數、以及各種函數,等等。
(4)、在前三個階段的基礎上,最終 VS 編譯器再將中間代碼(*.obj 文件)和其本身提供的庫文件(*.LIB)進行鏈接,最終產生可執行程序(Linux 系統使用的編譯器是:gcc,Linux 系統下面的可執行文件名可以任意,WINDOWS 系統下面的可執行文件名為:*.EXE 文件)。
到此為止,一個用戶編寫的源程序,經過上面若干步驟之後,最終產生了可執行程序,此時就可以在機器上的相應的操作系統上執行了。
❷ 編譯原理 什麼是靜態鏈
1、路由器的工作原理
路由工作簡單原理圖
在這里插入圖片描述
1)主機1.1要發生數據包給主機4.1.因為IP地址不在同一網段,所以主機會將數據包發送給本網段的網關路由器。
2)路由器A 接收到數據包,先查看數據包IP首部中的目標IP地址。再查找自己的路由表。數據包的目標IP地址是4.1.屬於4.0網段,路由器A 在路由表中查到4.0網段轉發的介面是S0介面,於是路由器A將數據從S0介面轉發出去。
3)網路中的每個路由器都是按照這樣的步驟轉發數據的,直到到達路由器B,再用同樣的方法從E0介面轉發出去,最後主機4.1接收到這個數據包。
2、路由表
(1)概念
路由器中維護的路由條目的集合。
路由器根據路由表做的路徑選擇。
(2)路由表的形成
1)直連網段
配置IP地址,埠UP 狀態,形成直連路由。
2)非直連網段
需要靜態路由或動態路由,將網段添加到路由表中。
3、靜態路由
由管理員手工配置的,是單向的。缺乏靈活性。
管理員可以通過靜態路由來控制數據包在網路中的流動。
4、默認路由
一種特殊的靜態路由,當路由器在路由表中找不到目標網路的路由條目時,路由器把請求轉發到默認路由介面。
當默認路由存在末梢網路時,默認路由會大大簡化路由器的配置。
5、路由器轉發數據包的分裝過程
HostA向HostB發送數據
在這里插入圖片描述
1)HostA在網路層將上層的報文封裝成IP數據包,其首部包含源地址和目的地址。源地址即本機IP地址192.168.1.2,目的地在為HostB的IP地址192.168.2.2,HostA使用本機配置的24位掩碼於目的地址進行「與」運算,得出目的地在與本機地址不在同一網段,因此發往HostB的數據包需要經過網關路由器A轉發。
2)HostA通過ARP請求獲得默認網關路由器A 的E0介面MAC 地址00-11-12-21-22-22.在數據鏈路層HostA將IP數據包封裝成乙太網數據幀,在乙太網首部的源MAC地址為00-11-12-21-11-11,目的MAC地址為網關E0介面的MAC地址00-11-12-21-22-22
3)路由器A從E0介面接收到數據幀,把數據鏈路層的封裝去掉。路由器A認為這個IP數據包是要通過自己進行路由轉發,所以路由器A會自己查找自己的路由表,尋找與目標IP地址192.168.2.2相匹配的路由表項,然後根據路由表的下一跳地址將數據包轉發到E1介面。
4)在E1介面路由器A 重新封裝乙太網幀,此時源MAC地址為路由器A的E1介面MAC地址00-11-12-21-33-33,目的MAC地址為與之相連的路由器B的E1介面MAC地址00-11-12-21-44-44
5)路由器B從E1介面接收到數據幀,同樣會吧數據鏈路層的封裝去掉。對目的IP地址進行檢查,並與路由表進行匹配,然後根據路由表的下一跳信息將數據包轉發到E0介面。路由器B發現目的網段與自己的E0介面相連,通過ARP廣播,路由器B獲得HostB以太口的MAC地址00-11-12-21-66-66.路由器B在將IP數據包封裝成乙太網幀,源MAC地址為路由器B的E0介面的MAC地址00-11-12-21-55-55,目的MAC地址為HostB的MAC地址00-11-12-21-66-66.封裝完畢,將乙太網幀從E0介面發往HostB.
❸ 求《編譯原理考研輔導教程》全文免費下載百度網盤資源,謝謝~
《編譯原理考研輔導教程》網路網盤pdf最新全集下載:
鏈接:https://pan..com/s/1d6s5KhHw8Ru3mccYMac7ZA
❹ C語言中編譯程序和連接程序的作用和原理是什麼關鍵是原理,越詳細越好,謝了~
詳細了你也不一定能理解,你對底層的了解程度如何?
簡單的來說編譯就是生成語言無關的obj文件,連接就是將所有的obj文件連接起來,查找裡面的符號按照COFF文件的標准生成dll或EXE。
❺ 編譯原理
C語言編譯過程詳解
C語言的編譯鏈接過程是要把我們編寫的一個C程序(源代碼)轉換成可以在硬體上運行的程序(可執行代碼),需要進行編譯和鏈接。編譯就是把文本形式源代碼翻譯為機器語言形式的目標文件的過程。鏈接是把目標文件、操作系統的啟動代碼和用到的庫文件進行組織形成最終生成可執行代碼的過程。過程圖解如下:
從圖上可以看到,整個代碼的編譯過程分為編譯和鏈接兩個過程,編譯對應圖中的大括弧括起的部分,其餘則為鏈接過程。
一、編譯過程
編譯過程又可以分成兩個階段:編譯和匯編。
1、編譯
編譯是讀取源程序(字元流),對之進行詞法和語法的分析,將高級語言指令轉換為功能等效的匯編代碼,源文件的編譯過程包含兩個主要階段:
第一個階段是預處理階段,在正式的編譯階段之前進行。預處理階段將根據已放置在文件中的預處理指令來修改源文件的內容。如#include指令就是一個預處理指令,它把頭文件的內容添加到.cpp文件中。這個在編譯之前修改源文件的方式提供了很大的靈活性,以適應不同的計算機和操作系統環境的限制。一個環境需要的代碼跟另一個環境所需的代碼可能有所不同,因為可用的硬體或操作系統是不同的。在許多情況下,可以把用於不同環境的代碼放在同一個文件中,再在預處理階段修改代碼,使之適應當前的環境。
主要是以下幾方面的處理:
(1)宏定義指令,如 #define a b。
對於這種偽指令,預編譯所要做的是將程序中的所有a用b替換,但作為字元串常量的 a則不被替換。還有 #undef,則將取消對某個宏的定義,使以後該串的出現不再被替換。
(2)條件編譯指令,如#ifdef,#ifndef,#else,#elif,#endif等。
這些偽指令的引入使得程序員可以通過定義不同的宏來決定編譯程序對哪些代碼進行處理。預編譯程序將根據有關的文件,將那些不必要的代碼過濾掉
(3) 頭文件包含指令,如#include "FileName"或者#include <FileName>等。
在頭文件中一般用偽指令#define定義了大量的宏(最常見的是字元常量),同時包含有各種外部符號的聲明。採用頭文件的目的主要是為了使某些定義可以供多個不同的C源程序使用。因為在需要用到這些定義的C源程序中,只需加上一條#include語句即可,而不必再在此文件中將這些定義重復一遍。預編譯程序將把頭文件中的定義統統都加入到它所產生的輸出文件中,以供編譯程序對之進行處理。包含到C源程序中的頭文件可以是系統提供的,這些頭文件一般被放在/usr/include目錄下。在程序中#include它們要使用尖括弧(<>)。另外開發人員也可以定義自己的頭文件,這些文件一般與C源程序放在同一目錄下,此時在#include中要用雙引號("")。
(4)特殊符號,預編譯程序可以識別一些特殊的符號。
例如在源程序中出現的LINE標識將被解釋為當前行號(十進制數),FILE則被解釋為當前被編譯的C源程序的名稱。預編譯程序對於在源程序中出現的這些串將用合適的值進行替換。
預編譯程序所完成的基本上是對源程序的「替代」工作。經過此種替代,生成一個沒有宏定義、沒有條件編譯指令、沒有特殊符號的輸出文件。這個文件的含義同沒有經過預處理的源文件是相同的,但內容有所不同。下一步,此輸出文件將作為編譯程序的輸出而被翻譯成為機器指令。
第二個階段編譯、優化階段。經過預編譯得到的輸出文件中,只有常量;如數字、字元串、變數的定義,以及C語言的關鍵字,如main,if,else,for,while,{,}, +,-,*,\等等。
編譯程序所要作得工作就是通過詞法分析和語法分析,在確認所有的指令都符合語法規則之後,將其翻譯成等價的中間代碼表示或匯編代碼。
優化處理是編譯系統中一項比較艱深的技術。它涉及到的問題不僅同編譯技術本身有關,而且同機器的硬體環境也有很大的關系。優化一部分是對中間代碼的優化。這種優化不依賴於具體的計算機。另一種優化則主要針對目標代碼的生成而進行的。
對於前一種優化,主要的工作是刪除公共表達式、循環優化(代碼外提、強度削弱、變換循環控制條件、已知量的合並等)、復寫傳播,以及無用賦值的刪除,等等。
後一種類型的優化同機器的硬體結構密切相關,最主要的是考慮是如何充分利用機器的各個硬體寄存器存放的有關變數的值,以減少對於內存的訪問次數。另外,如何根據機器硬體執行指令的特點(如流水線、RISC、CISC、VLIW等)而對指令進行一些調整使目標代碼比較短,執行的效率比較高,也是一個重要的研究課題。
2、匯編
匯編實際上指把匯編語言代碼翻譯成目標機器指令的過程。對於被翻譯系統處理的每一個C語言源程序,都將最終經過這一處理而得到相應的目標文件。目標文件中所存放的也就是與源程序等效的目標的機器語言代碼。目標文件由段組成。通常一個目標文件中至少有兩個段:
代碼段:該段中所包含的主要是程序的指令。該段一般是可讀和可執行的,但一般卻不可寫。
數據段:主要存放程序中要用到的各種全局變數或靜態的數據。一般數據段都是可讀,可寫,可執行的。
UNIX環境下主要有三種類型的目標文件:
(1)可重定位文件
其中包含有適合於其它目標文件鏈接來創建一個可執行的或者共享的目標文件的代碼和數據。
(2)共享的目標文件
這種文件存放了適合於在兩種上下文里鏈接的代碼和數據。
第一種是鏈接程序可把它與其它可重定位文件及共享的目標文件一起處理來創建另一個 目標文件;
第二種是動態鏈接程序將它與另一個可執行文件及其它的共享目標文件結合到一起,創建一個進程映象。
(3)可執行文件
它包含了一個可以被操作系統創建一個進程來執行之的文件。匯編程序生成的實際上是第一種類型的目標文件。對於後兩種還需要其他的一些處理方能得到,這個就是鏈接程序的工作了。
二、鏈接過程
由匯編程序生成的目標文件並不能立即就被執行,其中可能還有許多沒有解決的問題。
例如,某個源文件中的函數可能引用了另一個源文件中定義的某個符號(如變數或者函數調用等);在程序中可能調用了某個庫文件中的函數,等等。所有的這些問題,都需要經鏈接程序的處理方能得以解決。
鏈接程序的主要工作就是將有關的目標文件彼此相連接,也即將在一個文件中引用的符號同該符號在另外一個文件中的定義連接起來,使得所有的這些目標文件成為一個能夠被操作系統裝入執行的統一整體。
根據開發人員指定的同庫函數的鏈接方式的不同,鏈接處理可分為兩種:
(1)靜態鏈接
在這種鏈接方式下,函數的代碼將從其所在地靜態鏈接庫中被拷貝到最終的可執行程序中。這樣該程序在被執行時這些代碼將被裝入到該進程的虛擬地址空間中。靜態鏈接庫實際上是一個目標文件的集合,其中的每個文件含有庫中的一個或者一組相關函數的代碼。
(2) 動態鏈接
在此種方式下,函數的代碼被放到稱作是動態鏈接庫或共享對象的某個目標文件中。鏈接程序此時所作的只是在最終的可執行程序中記錄下共享對象的名字以及其它少量的登記信息。在此可執行文件被執行時,動態鏈接庫的全部內容將被映射到運行時相應進程的虛地址空間。動態鏈接程序將根據可執行程序中記錄的信息找到相應的函數代碼。
對於可執行文件中的函數調用,可分別採用動態鏈接或靜態鏈接的方法。使用動態鏈接能夠使最終的可執行文件比較短小,並且當共享對象被多個進程使用時能節約一些內存,因為在內存中只需要保存一份此共享對象的代碼。但並不是使用動態鏈接就一定比使用靜態鏈接要優越。在某些情況下動態鏈接可能帶來一些性能上損害。
我們在linux使用的gcc編譯器便是把以上的幾個過程進行捆綁,使用戶只使用一次命令就把編譯工作完成,這的確方便了編譯工作,但對於初學者了解編譯過程就很不利了,下圖便是gcc代理的編譯過程:
從上圖可以看到:
預編譯
將.c 文件轉化成 .i文件
使用的gcc命令是:gcc –E
對應於預處理命令cpp
編譯
將.c/.h文件轉換成.s文件
使用的gcc命令是:gcc –S
對應於編譯命令 cc –S
匯編
將.s 文件轉化成 .o文件
使用的gcc 命令是:gcc –c
對應於匯編命令是 as
鏈接
將.o文件轉化成可執行程序
使用的gcc 命令是: gcc
對應於鏈接命令是 ld
總結起來編譯過程就上面的四個過程:預編譯、編譯、匯編、鏈接。了解這四個過程中所做的工作,對我們理解頭文件、庫等的工作過程是有幫助的,而且清楚的了解編譯鏈接過程還對我們在編程時定位錯誤,以及編程時盡量調動編譯器的檢測錯誤會有很大的幫助的。
是否可以解決您的問題?
❻ 求《OPENMP編譯原理及實現技術》全文免費下載百度網盤資源,謝謝~
《OPENMP編譯原理及實現技術》網路網盤pdf最新全集下載:
鏈接:https://pan..com/s/122Xvd3cLwtzPFlh9XrJLUA
❼ 誰有 《 javapython編程語言含經典教材龍書《編譯原理》》電子版書籍百度網盤下載
《javapython編程語言含經典教材龍書》網路網盤免費資源下載:
鏈接: https://pan..com/s/1-r1_75u5ibOfCjTNEtnJow
Python解釋器易於擴展,可以使用C語言或C++(或者其他可以通過C調用的語言)擴展新的功能和數據類型。[4]Python 也可用於可定製化軟體中的擴展程序語言。Python豐富的標准庫,提供了適用於各個主要系統平台的源碼或機器碼。
❽ 編譯原理-編譯靜態庫並鏈接
編譯成.o 文件(目標文件)只需要包含頭文件,並且能找到頭文件路徑即可
之後需要把編譯好的 TestExample.o 名稱修改為 libTestExample.a ,直接當做靜態庫使用(靜態庫.a文件實際上是.o文件的合集)
或者使用下面的命令把.o打包成靜態庫
然後開始鏈接成可執行文件,mach-o文件
鏈接成功後,執行mach-o
看到列印,運行成功!
使用objmp 命令查看
整個編譯過程腳本:
❾ C語言編譯怎樣連接lib文件,請講解連接的原理,
廣義的代碼編譯過程,實際上應該細分為:預處理,編譯,匯編,鏈接。
預處理過程,負責頭文件展開,宏替換,條件編譯的選擇,刪除注釋等工作。gcc –E表示進行預處理。
編譯過程,負載將預處理生成的文件,經過詞法分析,語法分析,語義分析及優化後生成匯編文件。gcc –S表示進行編譯。
匯編,是將匯編代碼轉換為機器可執行指令的過程。通過使用gcc –C或者as命令完成。
鏈接,負載根據目標文件及所需的庫文件產生最終的可執行文件。鏈接主要解決了模塊間的相互引用的問題,分為地址和空間分配,符號解析和重定位幾個步驟。實
際上在編譯階段生成目標文件時,會暫時擱置那些外部引用,而這些外部引用就是在鏈接時進行確定的。鏈接器在鏈接時,會根據符號名稱去相應模塊中尋找對應符
號。待符號確定之後,鏈接器會重寫之前那些未確定的符號的地址,這個過程就是重定位。
❿ 編譯原理2-鏈接framework
使用libtool創建framework中的庫文件
雖然文件結構貌似一樣,但是不能直接使用libTestExample.a,需要通過libtool創建的靜態鏈接庫才行
之後才使用clang鏈接成可執行文件
以下為全部鏈接Framework生成可執行文件腳本