在 Visual Studio 中(筆者版本 Visual Studio 2017),新生成的C++項目文件的的頭文件夾下會默認有頭文件stdafx.h,而源文件夾下則默認有源文件stdafx.cpp,手動將這些文件刪除后,編譯時系統還會報錯。下面記錄筆者了解到的關於頭文件stdafx.h的信息。
使用預編譯頭
stdafx.h並不是標准C++頭文件,也就是說,該文件本質上相當於自定義的一個頭文件( 這里是VS默認自定義的文件),與項目的源代碼文件存放在同一個文件文件夾下,通過#include"stdafx.h"引用;
從內容上來說,頭文件stdafx.h中可以包含
1.標准系統包含文件
2.經常使用的但不常更改的特定於項目的包含文件
標准系統包含文件 : 即常用的與C標准庫對應的頭文件,如標准輸入頭文件stdio.h、字符串頭文件string.h等文件。
自定義的包含文件 : 即用戶根據項目需要自定義的頭文件。
在使用頭文件 stdafx.h 時,將所有源程序中所需的包含文件( .h 文件 )都包含在頭文件stdafx.h中,具體的做法就是將原本各個文件中所需要的類似於#include<stdio.h>的頭文件包含語句都存放在頭文件stdfax.h中,之后各個單獨的文件中不需要再對存在於stdafx.h中的頭文件進行單獨聲明,而只需要包含有頭文件stdafx.h即可。
#include"stdafx.h" //通過該語句包含頭文件stdafx.h,該語句需放在每個源文件文件的開頭,否則會報錯
同時,stdafx.h也可以存放內容改動較少的自定義的頭文件。
相應的,源文件stdafx.cpp中內容僅包含以下語句
#include "stdafx.h" //事實上,stdfax.cpp只用於編譯頭文件stdafx.h中包含的所有內容
事實上,stdafx.cpp只用於編譯頭文件stdafx.h中包含的所有內容。
開啟/關閉預編譯頭
選中目標項目,右鍵 -> 屬性 -> C/C++ -> 預編譯頭,在右側的選項中可以修改預編譯頭的相關設置。
1.可以修改選項為使用/不使用預編譯頭,從而開啟/關閉預編譯頭機制;
2.可以修改預編譯頭文件的名字(預編譯頭是一種機制,具體的頭文件名是可以自行指定的);
3.修改預編譯頭輸出文件的路徑;
實際上,每個單獨的源文件中均存在關於預編譯頭的屬性,用於指定不同的編譯策略,可供使用者自行選擇。特別的,源文件stdafx.cpp的預編譯頭屬性欄應設置為 創建(/Yc),這樣設置表示預編譯頭是由該源文件生成,而被其他文件使用。
預編譯頭的原理
在標准頭文件中,往往包含有大量的函數聲明、宏定義等方面的內容。一方面,原始預處理過程會將實際頭文件的內容復制到源程序中,這給編譯過程增加很大的開銷;另一方面,多個不同的單獨的源文件可能會重復聲明頭文件的包含關系來滿足傳統的函數聲明的要求,這也給編譯器帶來了重復勞動。另外,當文件發生修改時,整個文件需要重新編譯,而作為文件中內容不會更改的頭文件的內容也需要重新編譯,造成不必要的開銷。為了降低在編譯過程中諸如此類不必要的開銷,引入了預編譯頭的機制。
在編譯過程中,stdafx.cpp和stdafx.h文件用於生成一個預編譯頭文件 project.pch和預編譯類型文件stdafx.obj。
如前面提到的,stdafx.cpp存放的是#include "stdafx.h"。在第一次編譯過程中,stdafx.cpp首先被編譯處理,將頭文件stdafx.h中包含的所有的頭文件進行預編譯,從而生成一個預編譯頭文件project.pch,在之后的編譯過程中,只要stdafx.h沒有被修改(時間戳沒有發生改變),則編譯器可以直接使用預編譯頭文件project.pch的內容,而不需要重新編譯stdafx.h。之后的每個包含有stdafx.h頭文件的獨立文件編譯過程都會使用該pch文件中的內容,即一次集中編譯頭文件后,之后可重復使用。
實際上,生成預編譯頭文件同樣是耗時的,但是在后續的修改編譯過程中,只要沒有修改stdafx.h和stdafx.cpp文件的內容,就不需要重新生成預編譯頭文件,也就避免了許多頭文件處理的過程,從而大大減少了傳統重復處理頭文件的開銷。相應的,由於預編譯頭文件包含有眾多頭文件的處理信息,故而其本身會占用較大的存儲空間,故而可以注意清理不需要的預編譯頭。
一般來說,將被項目中多個獨立文件引用的標准頭文件和特定項目中一般不做修改的頭文件放在stdafx.h中可以大大提升程序編譯時的效率。
關於報錯
在使用預編譯頭機制時,可能會遇到一些問題
1. 無法打開預編譯頭文件"xxx.pch":no such file or directory 的問題
分析:根據上面的原理解釋,可能是由於編譯器無法通過stdafx.cpp創建一個預編譯文件,從而其他文件沒有辦法去引用該pch文件。
解決方案:選中源文件stdafx.cpp,右鍵 -> 屬性 -> C/C++ -> 預編譯頭,出現上述問題一般是由於預編譯頭的選項從 創建 變為了 使用 ,通過將選項重新改為創建可解決問題。
2. 在查找預編譯頭文件時遇到意外的文件結尾
需要將指令#include"stdafx.h" 放在每個文件的開始位置,以供處理。
參考:
Microsoft文檔:Precompiled header file
百度知道:C++ 中stdafx.h是什么意思
stackoverflow:問題的第一個答案