1. 程式人生 > >分離編譯模式簡介

分離編譯模式簡介

二次 生成可執行文件 () 這一 正是 特點 pac ron strong

http://blog.csdn.net/jiejinquanil/article/details/50984347

1、定義
分離編譯模式源於C語言,在C++語言中繼續沿用。簡單地說,分離編譯模式是指:一個程序(項目)由若幹個源文件共同實現,而每個源文件單獨編譯生成目標文件,最後將所有目標文件連接起來形成單一的可執行文件的過程。

2、分離編譯模式的由來
分離編譯模式是C/C++組織源代碼和生成可執行文件的方式。在實際開發大型項目的時候,不可能把所有的源程序都放在一個頭文件中,而是分別由不同的程序員開發不同的模塊,再將這些模塊匯總成為最終的可執行程序。
這裏就涉及到不同的模塊(源文件)定義的函數和變量之間的相互調用問題。C/C++語言所采用的方法是:只要給出函數原型(或外部變量聲明),就可以在本源文件中使用該函數(或變量)。每個源文件都是獨立的編譯單元,在當前源文件中使用但未在此定義的變量或者函數,就假設在其他的源文件中定義好了。每個源文件生成獨立的目標文件(obj文件),然後通過連接(Linking)將目標文件組成最終的可執行文件。
程序編譯的簡要過程包括預處理(Preprocessing)

編譯(Compilation)匯編(Assembly)連接(Linking)

3、分離編譯模式的的要點
(1)每個函數或外部變量(全局變量)只能被定義一次,但可以被多次“聲明”。見下面的程序:

#include <iostream>
using namespace std;
void func();
void func();
void func(){
         cout<<”This ia a demo”<<endl;
}
int main(){
         func();
}

函數func()被多次聲明,並不影響程序的正常編譯和運行。其實這正是C++分離編譯模式的特點之一。在一個源文件中允許同時包含定義和聲明同一個標識符的語句,這樣就有利於頭文件內容的組織。
(2)函數聲明也是有作用域的。


類的成員函數只能在類體中聲明。對於外部函數,如果是在一個函數體內聲明另一個外部函數,那麽該函數聲明的作用域就是從聲名處開始到函數體結束為止。在別的位置要調用這個函數,還必須再次聲明。
如下面的程序,由兩個源文件組成,a.cpp和b.cpp。函數func()定義在a.cpp中,b.cpp中有兩個函數show()和main()都調用了a.cpp中定義的函數func()。如果堅持將函數聲明放在函數體內部,則在函數show()和main()中必須分別對函數func()進行聲明,否則編譯出錯。程序如下:

/***a.cpp***/
#include <iostream>
Using namespace std;
void func(){
         cout<<”This is a demo”<<endl;
}
/***end of a.cpp***/

/****b.cpp****/
void show(){
void func(); //func()的聲明必不可少
    func();
}
int mian(){
         void func(); // func()的聲明必不可少
         func();
         show();
}
/****end of b.cpp****/

通常情況下,將外部函數或外部變量的聲明放在.h頭文件中。對於不在源文件中定義的函數(或變量),只要將相應的頭文件通過#include指令包含進來,就可以正常使用了。
(3)一個函數被聲明卻從未定義,只要沒有發生函數調用,編譯連接是不會出錯的。參考如下程序:

#include <iostream>
using namespace std;
class Demo{
public:
         void func1();
         void func2();
};
void Demo::func1(){
         cout<<”This is a demo”<<endl;
}
int main(){
         Demo obj;
obj.func1();
}

觀察以上程序可以,類Demo的定義是不完整的,因為成員函數func2未完成定義,但是func2從未發生過調用,所以,函數只有生命沒有定義在不發生函數調用的情況下是可以通過編譯連接的。
從分離編譯模式的角度來看,函數Demo::func2()有可能是在別的源文件中定義的。下面的程序就說明了這一點:

/****a.cpp****/    
#include <iostream>
using namespace std;
class Demo{
public:
     void func1();
     void func2();
};
void Demo::func2(){
     cout<<”This is func2”<<endl;
}       
/****end of a.cpp****/ 

/****b.cpp****/    
#include <iostream>
using namespace std;
class Demo{
public:
     void func1();
     void func2();
};
void Demo::func1(){
     cout<<”This is func1”<<endl;
}
int main(){
    Demo obj;
    obj.func2();
}
/****end of b.cpp****/ 

觀察以上程序,類Demo有兩個成員函數,它們分別在a.cpp和b.cpp源文件中實現。類Demo是被“分離“實現的。所以,分離編譯模式關心的是函數的調用規範(函數原型),至於函數是否真正實現要到連接的時候才能被發現。
由分離編譯模式也可以得到頭文件的書寫規範。頭文件的目的是提供其他源文件中定義的,可以被當前源文件使用的內容(函數、變量等)的聲明。因此,有個基本的假設是:頭文件要被多次被不同的源文件包含。因此,一般都不在頭文件中定義函數、定義外部變量,因為這樣的頭文件只能被包含一次,沒有被包含第二次的可能性,背離了設立頭文件的初衷。
在一個源文件中定義函數,在另一個源文件中調用該函數,是分離編譯模式下十分普遍的現象。但是如果定義的不是一個普通函數,而是一個函數模板,卻可能發生錯誤。

分離編譯模式簡介