有時我看到有人編譯這樣一個C程序:我是否需要在C程序中編譯頭文件?
gcc -o hello hello.c hello.h
據我所知,我們只是需要把頭文件到C程序,如:
#include "somefile"
和編譯C程序:gcc -o hello hello.c
。
我們什麼時候需要編譯頭文件或者爲什麼?
有時我看到有人編譯這樣一個C程序:我是否需要在C程序中編譯頭文件?
gcc -o hello hello.c hello.h
據我所知,我們只是需要把頭文件到C程序,如:
#include "somefile"
和編譯C程序:gcc -o hello hello.c
。
我們什麼時候需要編譯頭文件或者爲什麼?
首先,在一般:
如果這些.h
文件確實是典型的C風格的頭文件(而不是作爲完全不同的東西,只是碰巧與.h
擴展名來命名),則沒有,我們沒有理由以獨立地「編譯」這些頭文件。頭文件旨在包含在實現文件中,而不是作爲獨立的翻譯單元提供給編譯器。
由於典型的頭文件通常只包含可以在每個翻譯單元中安全地重複的聲明,所以「編譯」頭文件完全沒有不良後果。但同時它不會實現任何有用的功能。
基本上,編譯hello.h
作爲一個獨立的翻譯單元等效於創建一個簡併dummy.c
文件僅由#include "hello.h"
指令,和餵養dummy.c
文件給編譯器。它會編譯,但它沒有任何意義。
其次,專爲GCC:
許多編譯器會將不同,這取決於文件擴展名的文件。當GCC作爲命令行參數提供給編譯器時,GCC對.h
擴展名的文件有特殊處理。 GCC不是將其視爲常規翻譯單元,而是爲該.h
文件創建一個預編譯頭文件文件。
你可以閱讀一下:http://gcc.gnu.org/onlinedocs/gcc/Precompiled-Headers.html
所以,這是你可能會看到.h
文件被直接輸送到海灣合作委員會的原因。
好吧,讓我們來了解主動和被動代碼之間的區別。
活動代碼是函數,過程,方法的實現,即應編譯爲可執行機器代碼的代碼段。我們將它存儲在.c文件中,並確定我們需要編譯它。
被動代碼沒有被執行本身,但它需要解釋不同的模塊如何相互通信。通常,.h文件只包含原型(函數頭),結構。
宏是一個例外,它在形式上可以包含活動塊,但您應該明白,它們正在使用簡單替換構建(預處理)的最初階段使用。在編譯時,宏已經被替換爲你的.c文件。
另一個例外是C++模板,應該在.h文件中實現。但是這裏有一個類似於宏的故事:它們在早期階段(實例化)和形式化上被替代,其他實例化是另一種類型。
總之,我認爲,如果模塊正確形成,我們不應該編譯頭文件。
我認爲我們確實需要預處理(也許不會調用編譯)頭文件。因爲根據我的理解,在編譯階段,頭文件應該包含在c文件中。例如,在test.h我們有
typedef enum{
a,
b,
c
}test_t
和test.c的,我們在編譯過程中有
void foo()
{
test_t test;
...
}
,我覺得編譯器會放在頭文件和C文件中的代碼一起,頭文件中的代碼將被預處理並將代碼替換爲c文件中的代碼。同時,我們最好在makefile中定義包含路徑。
在某些系統中,嘗試加速完全解析的'.c'文件的組裝會調用預編譯include文件「編譯頭文件」。然而,這是一種優化技術,對於實際的C開發來說不是必需的。
這樣的技術基本上計算了包含語句並保留了扁平化包含的緩存。通常,C工具鏈將以遞歸方式剪切並粘貼包含的文件,然後將整個項目傳遞給編譯器。使用預編譯的頭緩存,工具鏈將檢查是否有任何輸入(定義,頭文件等)發生了變化。如果沒有,那麼它將提供已編排的文本文件片段給編譯器。
這樣的系統是爲了加速開發;然而,許多這樣的系統相當脆弱。隨着計算機速度的加快以及源代碼管理技術的改變,通用項目中實際使用的頭文件預編譯器數量更少。
直到您確實需要編譯優化,我強烈建議您避免預編譯頭文件。
比方說,你還沒有寫hello.c,但你有頭文件。然後你可以使用「gcc hello.h」來檢查頭文件的語法錯誤。否則,你必須創建一個包含hello.h的include語句的源文件(好吧,我想你無論如何都要這樣做)。 – Mark