2009-08-27 36 views
3

我有兩個半相關的問題。關於編譯和庫的兩個基本問題

我的第一個問題:我可以調用的標準庫函數沒有通過只是編譯整個庫:

#include <stdio.h> 

我怎麼會去與我的頭文件做同樣的事情?只是「包括」我的明文頭文件顯然不起作用。

#include "nameofmyheader.h" 

基本上,我該如何創建一個其他文件可以調用的庫?

第二個問題:假設我有一個程序被分成50個c文件和一個頭文件。什麼是除了編譯它的正確方法:

cc main.c 1.h 1.c 2.c 3.c 4.c 5.c 6.c 7.c /*... and so on*/ 

請糾正我有任何誤解。我完全迷失在這裏。

+0

您使用的平臺是?如果Windows我建議建立一個靜態庫或DLL,從外部代碼可以鏈接到這些靜態庫或DLL,但這些都是特定於Windows的 – 2009-08-27 10:27:48

回答

0

您需要創建一個共享庫,標準庫是一個共享庫,它隱式鏈接到您的程序中。

一旦你有你的共享庫可以使用.h文件,只是編譯-lyourlib至極方案是隱含的libc中

使用創建一個:

gcc -shared test.c -o libtest.so 

然後編譯程序,如:

gcc myprogram.c -ltest -o myprogram 

對於你的第二個問題,我建議你使用的Makefile http://www.gnu.org/software/make/

0

如果您真的希望它只是包含一個.h文件,那麼您的所有「庫」代碼都需要位於.h文件中。但是,在這種情況下,某人只能將.h文件包含到一個且僅包含一個.c文件中。這可能是好的,取決於某人將如何使用你的「圖書館」。

0

您可以將多個.c文件組合到一個庫中。這些庫可以與其他.c文件鏈接成可執行文件。

您可以使用makefile來創建一個大項目。

makefile有一組規則。每條規則描述了創建程序片段所需的步驟及其與其他片段或源文件的依賴關係。

0

標準庫已經編譯並放置在您的機器上以準備動態鏈接。這意味着庫在程序需要時動態加載。將它與一個靜態庫進行比較,該靜態庫在運行編譯器/鏈接器時被編譯到您的程序中。

這就是爲什麼你需要編譯你的代碼而不是標準的庫代碼。你可以自己建立一個動態(共享)庫。

僅供參考,#include <stdio.h>不是IMPORT標準庫。它只允許編譯和鏈接查看庫的公共接口(要知道使用了哪些函數,它們採用了哪些參數,定義了哪些類型,它們的大小等等)。

Dynamic Loading

Shared Library

你可以最多分裂文件成模塊,並創建共享庫。但是,一般來說,隨着項目變得越來越大,您往往需要更好的機制來構建您的程序(和庫)。當您需要重建時,不要直接調用編譯器,而應該使用make程序或像GNU Build System這樣的完整構建系統。

14

首先,你對#include會發生什麼感到困惑。你永遠不會「編譯」標準庫。標準庫已經被編譯並且位於庫文件中(Windows上的.dll和.lib文件,Linux上的.a和.so)。 #include所做的是將聲明所需的鏈接提供給標準庫。

理解#include指令的第一步是它們非常低級。如果您使用Java或Python進行編程,#includes與導入有很大不同。進口在較高級別上告訴編譯器「這個源文件需要使用這個包」,編譯器會指出如何解決這個依賴。 C指令中的#include指出:「在編譯時,將此文件的全部內容直接粘貼到這裏。」特別是,#include <stdio.h>引入了一個文件,該文件具有標準庫中所有I/O函數的前向聲明。然後,編譯代碼時,編譯器知道如何調用這些函數並檢查它們的類型是否正確。

一旦你的程序被編譯,它是鏈接到標準庫。這意味着您的鏈接器(由您的編譯器自動調用)將導致您的可執行文件使用共享標準庫(.dll或.so),或者將複製靜態標準庫(.lib或.a)到您的可執行文件中。在任何情況下,您的可執行文件都不會「包含」您不使用的標準庫的任何部分。

至於創建一個庫,這是一個複雜的話題,我會把它留給別人,特別是因爲我不認爲這是你真正想要根據你的問題的下一部分做什麼。

頭文件並不總是庫的一部分。看來你擁有的是多個源文件,並且你希望能夠使用另一個源文件中的源文件中的函數。你可以做到這一點,而無需創建一個庫。你需要做的就是把聲明作爲foo.c,你想從其他地方訪問到foo.h中。聲明就像函數原型和「extern」變量聲明一樣。例如,如果foo.c中包含

int some_global; 

void some_function(int a, char b) 
{ 
    /* Do some computation */ 
} 

然後,爲了使這些從其他源文件,foo.h中需要包含

extern int some_global; 

void some_function(int, char); 

然後訪問,你#include "foo.h"無論你想使用some_global或some_function。由於標題可以包含其他標題,因此通常會將標題封裝在「包含標題」中,以便不重複聲明。例如,foo.h中真的應該讀:

#ifndef FOO_H 
#define FOO_H 

extern int some_global; 

void some_function(int, char); 

#endif 

這意味着該標題將僅每編譯單元(源文件)一旦被處理。

至於如何編譯它們,切勿將.h文件放在編譯器命令行上,因爲它們不應該包含任何可編譯的代碼(只有聲明)。在大多數情況下,是完全沒有編譯爲

cc main.c 1.c 2.c 3.c ... [etc] 

不過,如果你有50個源文件,它可能是方便多了,如果你使用的編譯系統。在Linux上,這是一個Makefile。在Windows上,它取決於你使用的開發環境。你可以谷歌的,或者一旦你指定你的平臺問另一個SO問題(因爲這個問題已經很廣泛了)。

構建系統的優點之一是它們獨立地編譯每個源文件,然後將它們全部鏈接在一起,以便當只更改一個源文件時,只需要重新編譯該文件(並且程序重新鏈接),而不是重新編譯所有內容,包括沒有更改的內容。當程序變大時,這會造成很大的時間差。

+0

+1良好的答案! – Avi 2009-08-27 10:46:04

+1

我希望我能+2這個。做得好。明確提出。 – 2009-08-27 11:48:56

+0

感謝您的清除。這正是我需要的解釋。 – overcyn 2009-08-27 11:50:51