2016-11-15 91 views
6

我有麻煩讓預編譯頭文件工作,所以我想出了以下最小工作示例。使用gcc預編譯頭文件的怪異行爲

這是頭文件foo.h

#include <iostream> 
using namespace std; 

void hello() { 
    cout << "Hello World" << endl; 
} 

我編譯這是g++ -c foo.h給了我一個編譯頭foo.gch。我期望當我編譯包含foo.h的以下源文件時,它應該選擇標頭foo.h.gch,我很好。

// test.cpp 
#include <cstdio> // Swap ordering later 
#include "foo.h" // ------------------ 

int main() { 
    hello(); 
} 

但出乎意料的是,這並不編譯使用foo.h.gch,而是使用foo.h。爲了驗證你可以編譯以此爲g++ -H test.cpp

但是,如果我改變包含的頭文件的順序如下:

// test.cpp 
#include "foo.h" // ------------------ 
#include <cstdio> // Ordering swapped 

int main() { 
    hello(); 
} 

現在,如果我編譯使用g++ -H test.cpp,從foo.h.gch編譯,噢!

所以我想知道這是否是GCC中的錯誤,或者我們是否應該使用預編譯的頭文件?在這兩種情況下,我認爲它有用知道..

回答

4

隨着GCC,預編譯頭工作只有如果他們是只有頭,如果他們都首先包含(之前沒有任何頭)。

This answer解釋更多爲什麼如此。 參見GCC文檔,它說的Precompiled headers章:

  • 只有一個預編譯頭可以在特定編譯使用。
  • 一旦看到第一個C令牌,就不能使用預編譯頭。

BTW,是可能發生的預編譯一些大的報頭(特別是C++)是不值得的。因人而異。

+1

在我的情況下,它似乎是超級有效的!我正在預編譯CGAL頭文件,並將編譯時間從18秒縮短到2秒。 – sud03r

4

從GCC manual pages

一旦該第一C令牌被認爲是預編譯的報頭不能被使用。

所以包括<cstdio>在你的預編譯頭文件或首先包含它將工作。

+0

感謝您的回答!當然,這是記錄:)。如果只有程序員(或者像我這樣不耐煩的程序員)可以通讀它們。 – sud03r

3

簡而言之,預編譯的頭事情的作品這樣的:

當您請求創建一個「.PCH」文件,編譯器處理源文件如常。儘管如此,它的內部結構(主要是名稱表和所有相關數據)也已填充。最後,它會對這些內部結構進行快照並將其保存到'.pch'文件中。

之後,編譯包含頭部的源文件時,會出現'。pch'文件存在的情況下,編譯器可以省略昂貴的頭文件處理,而是從「.pch」文件加載準備好的快照。

顯然,這可以在不影響語義來完成,僅當:

  • 納入指令來先天下之憂;
  • 編譯器選項是相同的。

凡是列入指令之前出現可能:

  • 添加一些編譯器的內部數據結構;
  • 影響頭文件的處理;
  • 改變那裏描述的實體之間的關係。

因此,在這種情況下,加載內部數據結構的快照將是錯誤的,因爲不能保證它將使這些結構處於與正常處理標頭後相同的狀態。