程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 有關C++頭文件的包括順序研討

有關C++頭文件的包括順序研討

編輯:關於C++

有關C++頭文件的包括順序研討。本站提示廣大學習愛好者:(有關C++頭文件的包括順序研討)文章只能為提供參考,不一定能成為您想要的結果。以下是有關C++頭文件的包括順序研討正文


一.《Google C++ 編程作風指南》裡的觀念

公司在推行編碼標准,指導提議根本上運用《Google C++ 編程作風指南》。

其中《Google C++ 編程作風指南》關於頭文件的包括順序是這樣的:
 
Names and Order of Includes
link ▽Use standard order for readability and to avoid hidden dependencies:C library, C++ library, other libraries' .h, your project's .h.
All of a project's header files should belisted as descendants of the project's source directory without use of UNIXdirectory shortcuts . (the current directory) or .. (the parent directory). Forexample, google-awesome-project/src/base/logging.h should be included as
 
#include "base/logging.h"
In dir/foo.cc or dir/foo_test.cc, whosemain purpose is to implement or test the stuff in dir2/foo2.h, order yourincludes as follows:
 
dir2/foo2.h (preferred location — seedetails below).
C system files.
C++ system files.
Other libraries' .h files.
Your project's .h files.
The preferred ordering reduces hiddendependencies. We want every header file to be compilable on its own. Theeasiest way to achieve this is to make sure that every one of them is the first.h file #included in some .cc.
 
dir/foo.cc and dir2/foo2.h are often in thesame directory (e.g. base/basictypes_test.cc and base/basictypes.h), but can bein different directories too.
 
Within each section it is nice to order theincludes alphabetically.
 
For example, the includes ingoogle-awesome-project/src/foo/internal/fooserver.cc might look like this:

<span > 
#include "foo/public/fooserver.h" // Preferred location. 
 
#include <sys/types.h> 
 
#include <unistd.h> 
 
  
 
#include <hash_map> 
 
#include <vector> 
 
  
 
#include "base/basictypes.h" 
 
#include"base/commandlineflags.h" 
 
#include "foo/public/bar.h" 
 
 </span> 

在這裡我談一下我對下面的了解(如不當,還請諸位同窗指正):

1. 為了增強可讀性和防止隱含依賴,應運用上面的順序:C規范庫、C++規范庫、其它庫的頭文件、你自己工程的頭文件。不過這裡最先包括的是首選的頭文件,即例如a.cpp文件中應該優先包括a.h。首選的頭文件是為了增加隱藏依賴,同時確保頭文件和完成文件是婚配的。詳細的例子是:假設你有一個cc文件(Linux平台的cpp文件後綴為cc)是google-awesome-project/src/foo/internal/fooserver.cc,那麼它所包括的頭文件的順序如下:

<span >#include "foo/public/fooserver.h" // Preferred location. 
 
#include <sys/types.h> 
#include <unistd.h> 
 
#include <hash_map> 
#include <vector> 
 
#include "base/basictypes.h" 
#include "base/commandlineflags.h" 
#include "foo/public/bar.h" 
 
</span> 

2. 在包括頭文件時應該加上頭文件所在工程的文件夾名,即假設你有這樣一個工程base,外面有一個logging.h,那麼內部包括這個頭文件應該這樣寫:

#include "base/logging.h",而不是#include "logging.h"
 
我們看到的是這裡《Google C++ 編程作風指南》倡議的准繩面前隱藏的目的是:

1. 為了增加隱藏依賴,同時頭文件和其完成文件婚配,應該先包括其首選項(即其對應的頭文件)。
 
2. 除了首選項外,遵照的是從普通到特殊的准繩。不過我覺得《Google C++ 編程作風指南》的順序:C規范庫、C++規范庫、其它庫的頭文件、你自己工程的頭文件中漏了最後面的一項:操作零碎級別的頭文件,比方下面的例子sys/types.h估量不能歸入C規范庫,而是Linux操作零碎提供的SDK吧。因而我覺得更精確的說法應該是:OS SDK .h , C規范庫、C++規范庫、其它庫的頭文件、你自己工程的頭文件。
 
3.之所以要將頭文件所在的工程目錄列出,作用應該是命名空間是一樣的,就是為了區分不小心形成的文件重名。
 
二.《C++編程思想》中的不同觀念
  
與《Google C++ 編程作風指南》不同的是,《C++編程思想》倡議一種不同的規則。《C++編程思想》P432提到:

頭文件被包括的順序是從“最特殊到最普通”。這就是,在本地目錄的任何頭文件首先被包括。然後是我們自己的一切“工具”頭文件,隨後是第三方庫頭文件,接著是規范C++庫頭文件和C庫頭文件。

要理解其緣由:可以看JohnLakos在《Large ScaleC++ Softwre Design》(注:其中文譯名為《大規模C++順序設計》)中的一段話:
 
保證.h文件的組成局部不被它本身解析(parse),這可以防止潛在的運用錯誤。由於被本身解析缺乏明白提供的聲明或定義。在.c文件的第一行包括.h 文件能確保一切關於構件的物理界面重要的外部信息塊都在.h中(假如確實是短少了某些信息塊,一旦編譯這個.c文件時就可以發現這個問題)。
 
假如包括頭文件的順序是“從最特殊到最普通”,假如我們的頭文件不被它自己解析。我們將馬上找到它,避免費事事情發作。
 
三.我的實驗
 
究竟哪一種包括順序好呢?我運用VS 2005編一個控制台測試工程TestInc,外面有幾個文件。
 
MyMath.h的代碼如下:

<span >#pragma once 
 
#pragma once 
double acos(double Num); 
</span> 

MyMath.cpp的代碼如下:

<span >double acos(double Num) 
{ 
  return 1.0; 
} 
 
</span> 

TestInc.cpp的代碼如下:

<span >#include "stdafx.h" 
#include "TestInc.h" 
#include <stdio.h> 
#include <math.h> 
 
 
int _tmain(int argc, _TCHAR* argv[]) 
{ 
  double a = acos(0.5); 
  return 0; 
} 
</span> 

後果呈現錯誤:

1>c:\program files\microsoft visualstudio 8\vc\include\math.h(107) : error C2732: 鏈接標准與“acos”的晚期標准抵觸
1>  c:\program files\microsoft visual studio 8\vc\include\math.h(107) : 參見“acos”的聲明
 
然後我把TestInc.cpp的頭文件包括順序改為:

<span >#include "stdafx.h" 
#include <stdio.h> 
#include <math.h> 
#include "TestInc.h" 
</span> 

則編譯經過了。在調試運轉時main函數調用還是C規范庫的函數acos,看來函數調用的順序是按頭文件的包括順序來的,即我自定義的acos函數被掩蓋了(假如TestInc.h裡包括了內聯函數,則優先調用的是內聯函數)。
 
從這個小實驗中我得出如下結論:《Google C++ 編程作風指南》和《C++編程思想》倡議的包括頭文件的順序各有優點,《Google C++ 編程作風指南》應該能少量增加隱藏的頭文件依賴,而《C++編程思想》則很容易讓你清楚知道你所定義的接口能否和零碎庫落第三方庫發作抵觸。
 
四.頭文件包括中的預編譯功用
 
在Visual Studio環境下開發我們發現簡直每個cpp文件都要包括stdafx.h這個文件,而且要把它放在最後面的地位,否則就會出錯。這是為什麼呢?
 
原來Visual Studio采用一種預編譯的機制。要理解預編譯機制,先引見一下預編譯頭。所謂的預編譯頭就是把一個工程中的那一局部代碼,事後編譯好放在一個文件裡(通常是以.pch為擴展名的),這個文件就稱為預編譯頭文件這些事後編譯好的代碼可以是任何的C/C++代碼,甚至是inline的函數,但是必需是波動的,在工程開發的進程中不會被常常改動。假如這些代碼被修正,則需求重新編譯生成預編譯頭文件。留意生成預編譯頭文件是很耗時間的。同時你得留意預編譯頭文件通常很大,通常有6- 7M大。留意及時清算那些沒有用的預編譯頭文件。
 
也許你會問:如今的編譯器都有Time stamp的功用,編譯器在編譯整個工程的時分,它只會編譯那些經過修正的文件,而不會去編譯那些從上次編譯過,到如今沒有被修正過的文件。那麼為什麼還要預編譯頭文件呢?答案在這裡,我們知道編譯器是以文件為單位編譯的,一個文件經過修正後,會重新編譯整個文件,當然在這個文件裡包括的一切頭文件中的東西(.eg Macro, Preprocessor )都要重新處置一遍。 VC的預編譯頭文件保管的正是這局部信息。以防止每次都要重新處置這些頭文件。
 
依據上文引見,預編譯頭文件的作用當然就是進步廉價速度了,有了它你沒有必要每次都編譯那些不需求常常改動的代碼。編譯功能當然就進步了。
 
要運用預編譯頭,我們必需指定一個頭文件,這個頭文件包括我們不會常常改動的代碼和其他的頭文件,然後我們用這個頭文件來生成一個預編譯頭文件(.pch 文件)想必大家都知道StdAfx.h這個文件。很多人都以為這是VC提供的一個“零碎級別”的,編譯器帶的一個頭文件。其實不是的,這個文件可以是任何名字的。我們來調查一個典型的由AppWizard生成的MFC Dialog Based 順序的預編譯頭文件。(由於AppWizard會為我們指定好如何運用預編譯頭文件,默許的是StdAfx.h,這是VC起的名字)。我們會發現這個頭文件裡包括了以下的頭文件:

<span >#include <afxwin.h> // MFC core and standard components 
#include <afxext.h> // MFC extensions 
#include <afxdisp.h> // MFC Automation classes 
#include <afxdtctl.h> // MFC support for Internet Explorer 4 Common Controls 
#include <afxcmn.h> 
</span> 

這些正是運用MFC的必需包括的頭文件,當然我們不太能夠在我們的工程中修正這些頭文件的,所以說他們是波動的。
 
那麼我們如何指定它來生成預編譯頭文件。我們知道一個頭文件是不能編譯的。所以我們還需求一個cpp文件來生成.pch 文件。這個文件默許的就是StdAfx.cpp。在這個文件裡只要一句代碼就是:#include“Stdafx.h”。緣由是天經地義的,我們僅僅是要它可以編譯而已―――也就是說,要的只是它的.cpp的擴展名。我們可以用/Yc編譯開關來指定StdAfx.cpp來生成一個.pch文件,經過/Fp 編譯開關來指定生成的pch文件的名字。翻開project ->Setting->C/C++ 對話框。把Category指向Precompiled Header。在右邊的樹形視圖裡選擇整個工程,Project Options(右下角的那個白的中央)可以看到 /Fp “debug/PCH.pch”,這就是指定生成的.pch文件的名字,默許的通常是 <工程名>.pch。然後,在右邊的樹形視圖裡選擇 StdAfx.cpp,這時原來的Project Option變成了 Source File Option(原來是工程,如今是一個文件,當然變了)。在這裡我們可以看到 /Yc開關,/Yc的作用就是指定這個文件來創立一個Pch文件。/Yc前面的文件名是那個包括了波動代碼的頭文件,一個工程裡只能有一個文件的可以有 YC開關。VC就依據這個選項把 StdAfx.cpp編譯成一個Obj文件和一個PCH文件。

這樣,我們就設置好了預編譯頭文件。也就是說,我們可以運用預編譯頭功用了。

以下是留意事項:
 
1)假如運用了/Yu,就是說運用了預編譯,我們在每個.cpp文件的最掃尾,包括你指定發生pch文件的.h文件(默許是stdafx.h)不然就會有問題。假如你沒有包括這個文件,就通知你Unexpected file end.
 
2)假如你把pch文件不小心丟了,依據以上的剖析,你只需讓編譯器生成一個pch文件就可以了。也就是說把stdafx.cpp(即指定/Yc的那個cpp文件)重新編譯一遍就可以了。   

那麼在Linux平台下有沒有這種預編譯機制呢?假如有,它是怎樣完成的呢?Linux平台下GCC編譯器也完成了預編譯機制的。這裡以開源IDE CodeBlocks(CodeBlocks內置了GCC編譯器)的工程為例來闡明Linux平台的完成:
 
運用CodeBlocks建一個C++工程,然後新建一個my_pch.h,輸出如下代碼:

<span >/*************************************************************** 
 * Name:   my_pch.h 
 * Purpose:  Header to create Pre-Compiled Header (PCH) 
 * Author:   () 

 * Copyright: () 
 * License: 
 * 運用辦法: 項目構建選項-->其他選項-->填入上面兩行 
 -Winvalid-pch 
 -include my_pch.h 
 **************************************************************/ 
 
#ifndef MY_PCH_H_INCLUDED 
#define MY_PCH_H_INCLUDED 
 
// put here all your rarely-changing header files 
 
#include <iostream> 
#include <string> 
 
#endif 
</span> 

然後在項目構建選項-->其他選項-->填入上面兩行

 -Winvalid-pch
 -include my_pch.h

就可以啟用預編譯文件頭。
然後 main.cpp 就可以不必 include 頭文件了,直接這樣就可以編譯了,

<span >int main() 
{  
using namespace std; 
  cout << "Hello world!" << endl; 
  return 0; 
} 
</span> 

即便在下面的代碼寫上上面一行,其實是不起作用的:

<span >#include <iostream> </span> 

以上就是為大家帶來的有關C++頭文件的包括順序研討全部內容了,希望大家多多支持~

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved