找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 3967|回复: 15

C++头文件的包罗次序研究

  [复制链接]

4

主题

435

回帖

2549

积分

高级会员

积分
2549
发表于 2018-9-15 23:33:43 | 显示全部楼层 |阅读模式
一.《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:


#include "foo/public/fooserver.h"  // Preferred location.
#include
#include
#include
#include
#include "base/basictypes.h"
#include"base/commandlineflags.h"
#include "foo/public/bar.h"


在这里我谈一下我对上面的明白(如不妥,还请诸位同砚指正):


1.      为了增强可读性和制止隐含依靠,应利用下面的次序:C尺度库、C++尺度库、别的库的头文件、你本身工程的头文件。不外这里开始包罗的是首选的头文件,即比方a.cpp文件中应该优先包罗a.h。首选的头文件是为了淘汰隐蔽依靠,同时确保头文件和实现文件是匹配的。详细的例子是:如果你有一个cc文件(linux平台的cpp文件后缀为cc)是google-awesome-project/src/foo/internal/fooserver.cc,那么它所包罗的头文件的次序如下:


#include   
#include   
  
#include   
#include   
  
#include "base/basictypes.h"  
#include "base/commandlineflags.h"  
#include "foo/public/bar.h"


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的代码如下:


#pragma once  
[color=#800080 !important]double[color=#006FE0 !important] [color=teal !important]acos[color=#333333 !important]([color=#800080 !important]double[color=#006FE0 !important] [color=#002D7A !important]Num[color=#333333 !important]);


MyMath.cpp的代码如下:


[color=#800080 !important]double[color=#006FE0 !important] [color=teal !important]acos[color=#333333 !important]([color=#800080 !important]double[color=#006FE0 !important] [color=#002D7A !important]Num[color=#333333 !important])[color=#006FE0 !important]  
{  
[color=#006FE0 !important]    return[color=#006FE0 !important] [color=#009999 !important]1.0[color=#333333 !important];[color=#006FE0 !important]  
}


TestInc.cpp的代码如下:


#include "TestInc.h"  
#include   
#include  
[color=#006FE0 !important]  
[color=#800080 !important]int[color=#006FE0 !important] [color=teal !important]_tmain[color=#333333 !important]([color=#800080 !important]int[color=#006FE0 !important] [color=#002D7A !important]argc[color=#333333 !important],[color=#006FE0 !important] [color=teal !important]_TCHAR*[color=#006FE0 !important] [color=#002D7A !important]argv[color=#333333 !important][])[color=#006FE0 !important]  
{  
[color=#006FE0 !important]    [color=#800080 !important]double[color=#006FE0 !important] [color=#002D7A !important]a[color=#006FE0 !important] = [color=teal !important]acos[color=#333333 !important]([color=#009999 !important]0.5[color=#333333 !important]);[color=#006FE0 !important]  
[color=#006FE0 !important]    return[color=#006FE0 !important] [color=#009999 !important]0[color=#333333 !important];[color=#006FE0 !important]  
}


效果出现错误:


1>c:program filesmicrosoft visualstudio 8vcincludemath.h(107) : error C2732: 链接规范与“acos”的早期规范辩论


1>       c:program filesmicrosoft visual studio 8vcincludemath.h(107) : 拜见“acos”的声明


然后我把TestInc.cpp的头文件包罗次序改为:


#include   
#include   
#include "TestInc.h"


则编译通过了。在调试运行时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起的名字)。我们会发现这个头文件里包罗了以下的头文件:


#include  // MFC extensions  
#include  // MFC Automation classes
#include  // MFC support for Internet Explorer 4 Common Controls
#include


这些正是利用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,输入如下代码:


/***************************************************************
* Name:      my_pch.h
* Purpose:   Header to create Pre-Compiled Header (PCH)
* Author:     ()
* Created:   2010-10-26
* 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   
#include   
  
#endif


然后在项目构建选项–>其他选项–>填入下面两行


[color=#006FE0 !important]-[color=#002D7A !important]Winvalid[color=#006FE0 !important]-[color=#002D7A !important]pch
[color=#006FE0 !important]-[color=teal !important]include [color=#002D7A !important]my_pch[color=#333333 !important].[color=#002D7A !important]h


就可以启用预编译文件头。


然后 main.cpp 就可以不消 include 头文件了,直接如许就可以编译了


<blockquote>[color=#800080 !important]int[color=#006FE0 !important] [color=teal !important]main[color=#333333 !important]()[color=#006FE0 !important]  
{  
[color=teal !important]using [color=#800080 !important]namespace[color=#006FE0 !important] [color=#002D7A !important]std[color=#333333 !important];[color=#006FE0 !important]  

<span style="font-size: 12px;">[color=#006FE0 !important]    [color=#002D7A !important]cout<span class="crayon-h" style="border-width: 0px; border-style: initial; border-color: initial; font-family: inherit; height: inherit; font-size: inherit !important; line-height: inherit !important; font-weight: inherit !important; color: rgb(0, 111, 224) !important;">
工控课堂 www.gkket.com

0

主题

439

回帖

2867

积分

高级会员

积分
2867
发表于 2018-10-3 18:19:22 | 显示全部楼层
激动人心,无法言表!
工控课堂 www.gkket.com

6

主题

429

回帖

2739

积分

高级会员

积分
2739
发表于 2018-12-29 08:22:24 | 显示全部楼层
绝对干货,楼主给力,支持了!!!
工控课堂 www.gkket.com

0

主题

437

回帖

2652

积分

高级会员

积分
2652
发表于 2019-3-23 04:07:24 | 显示全部楼层
看完楼主的帖子,我的心情竟是久久不能平息,受教了
工控课堂 www.gkket.com

10

主题

441

回帖

2906

积分

高级会员

积分
2906
发表于 2019-4-17 18:08:57 | 显示全部楼层
加油,加油,不要沉下去,我是最热贴
工控课堂 www.gkket.com

8

主题

422

回帖

2820

积分

高级会员

积分
2820
发表于 2019-4-18 15:02:43 | 显示全部楼层
强烈支持楼主ing……
工控课堂 www.gkket.com

0

主题

91

回帖

139

积分

新手上路

积分
139
发表于 2025-11-17 01:19:12 | 显示全部楼层
来凑个热闹,为楼主增加点人气!
工控课堂 www.gkket.com

0

主题

90

回帖

135

积分

新手上路

积分
135
发表于 2025-11-18 21:56:31 | 显示全部楼层
理性围观,感觉大家说得都有道理
工控课堂 www.gkket.com

0

主题

91

回帖

136

积分

新手上路

积分
136
发表于 2025-11-20 09:59:53 | 显示全部楼层
楼主辛苦啦,期待下一篇分享
工控课堂 www.gkket.com

0

主题

36

回帖

23

积分

新手上路

积分
23
发表于 2025-11-20 10:10:52 | 显示全部楼层
这评论区卧虎藏龙,个个都是人才!
工控课堂 www.gkket.com
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

站长推荐上一条 /1 下一条

QQ|手机版|免责声明|本站介绍|工控课堂 ( 沪ICP备20008691号-1 )

GMT+8, 2025-12-22 15:38 , Processed in 0.096691 second(s), 29 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表