An inclusion order study of C++ header files

  • 2020-05-10 18:35:15
  • OfStack

1. Ideas from the Google C++ programming style guide

The company is pushing for a coding specification, and the leadership is proposing to basically use the Google C++ programming style guide.

The Google C++ programming style guide includes header files in the following order:
 
Names and Order of Includes
link standard for readability and avoid 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 style="font-size:16px;"> 
#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> 

Here I would like to talk about 1 of my understanding of the above (if inappropriate, please correct) :

1. To enhance readability and avoid implicit dependencies, use the following order: C standard library, C++ standard library, headers from other libraries, and headers from your own project. However, the first to be included here is the preferred header file, i.e. a.h should be included first in the a.cpp file. The preferred header file is to reduce hidden dependencies while ensuring that the header file and the implementation file match. Concrete example is: if you have a cc file (Linux platform cpp file suffix cc) is google - awesome - project/src foo/internal/fooserver cc, it contains header files as follows:


<span style="font-size:16px;">#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. If you have a project base with an logging.h inside, you should include the header file as follows:

#include "base/ logging.h "instead of #include" logging.h"
 
What we see here in the Google C++ programming style guide is the underlying purpose behind the principles advocated here:

1. To reduce hidden dependencies and to match the header file to its implementation file, include its preferences (that is, its corresponding header file) first.
 
2. In addition to the preferences, follow the principle from 1 to special. However, I think the order of Google C++ programming style guide: C standard library, C++ standard library, other library header file, your own project header file missing the first item: operating system level header file, such as the above example sys/types.h is probably not included in C standard library, but SDK provided by Linux operating system. So I think it would be more accurate to say: OS SDK.h, C standard library, C++ standard library, headers from other libraries, headers from your own project.
 
3. The reason to list the project directory where the header file is located, the effect should be that the namespace is 1, in order to distinguish accidentally caused by the file name.
 
2. A different view from C++ programming ideas
   
Unlike Google C++ programming style guide, C++ programming ideas advocates a different set of rules. C++ programming ideas, P432 mentions:

Header files are included in the order from "most special to most 1". That is, any header file in the local directory is included first. Then we have all our own "tools" headers, followed by the third party library header, followed by the standard C++ library header and C library header.

To understand why, read JohnLakos's first paragraph in Large ScaleC++ Softwre Design:
 
Ensure that the components of the.h file are not parsed by itself (parse), which avoids potential usage errors. Because it is resolved by itself without explicitly providing a declaration or definition. Including the.h file in line 1 of the.c file ensures that all internal information blocks that are important to the physical interface of the component are in.h. (if certain information blocks are missing, you will find this when you compile the.c file.)
 
If the order of containing header files is "from most special to most 1", if our header file is not parsed by itself. We'll find it immediately to prevent trouble.
 
3. My test
 
Which one is the better one? I used VS 2005 to compile a console to test project TestInc, which contained several files.
 
The code for MyMath.h is as follows:


<span style="font-size:16px;">#pragma once 
 
#pragma once 
double acos(double Num); 
</span> 

The code for MyMath. cpp is as follows:


<span style="font-size:16px;">double acos(double Num) 
{ 
  return 1.0; 
} 
 
</span> 

The code of TestInc.cpp is as follows:


<span style="font-size:16px;">#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> 

Error:

1 > c:\program files\microsoft visualstudio 8\vc\include\ math. h(107) : error C2732: link specification conflicts with the earlier specification of "acos"
1 >           c:\program files studio vc\include\ math. h(107) : see the statement "acos"
 
Then I changed the TestInc.cpp header file include order to:


<span style="font-size:16px;">#include "stdafx.h" 
#include <stdio.h> 
#include <math.h> 
#include "TestInc.h" 
</span> 

The compiler passed. During the debug run, the main function is still called as acos from the standard C library. It seems that the order of function calls is in the order of header file inclusion, that is, my custom acos function is overwritten (if TestInc.h contains inline functions, then the inline function is preferred).
 
From this little experiment I draw the following conclusion: the Google C + + programming style guide "and" C + + programming ideas advocated by the "include the header files in the order of each have advantages, the Google C + + programming style guide should be able to substantially reduce hidden header file dependence, whereas the C + + programming ideas, it's easy to let you know whether you are defined by the interface and system library 3 (superscript rd) party libraries.
 
4. Precompile functionality included in the header file
 
When developed in the Visual Studio environment, we found that almost every cpp file must contain the stdafx.h file, and it must be placed at the front of the file, otherwise an error will occur. Why is that?
           
The original Visual Studio USES a precompiled mechanism. To understand the precompile mechanism, first introduce the precompile header 1. So-called precompiled header is the one that 1 part of the project code, precompiled good in one file (usually in. pch extension), the file is called a precompiled header file these previously compiled code can be any C/C + + code, or even inline function, but must be stable, in the process of project development will not be constantly changing. If the code is modified, you need to recompile to generate the precompiled header file. Note that generating precompiled header files is time consuming. Also note that precompiled header files are usually large, usually as large as 6-7M. Be careful to clean up unused precompiled header files in a timely manner.
 
You may ask: the current compiler has the function of Time stamp. When the compiler compiles the whole project, it will only compile the files that have been modified, and will not compile the files that have not been modified since the last time it was compiled. So why precompile header files? Here's the answer. We know that the compiler compiles files on a file basis. Once a file is modified, it recompiles the entire file. Of course, all the header files contained in this file (.eg Macro, Preprocessor) have to be reprocessed once. It is this information that is stored in the precompiled header file of VC. To avoid having to reprocess these header files every time.
 
According to the above, the purpose of precompiling header files is of course to improve the speed. With it, you don't have to compile code every time that doesn't need to be changed frequently. Compilation performance certainly improved.
 
To use a precompiled header, we have to specify a header file that contains code that we don't change very often and other header files, and then we use this header file to generate a precompiled header file (.pch) that you probably know about StdAfx.h. Many people assume that this is a "system level" compiler header file provided by VC. No, the file can be any name. Let's look at a precompiled header file for a typical MFC Dialog Based program generated by AppWizard. (because AppWizard specifies for us how to use the precompiled header file, the default is StdAfx.h, as VC is called). We will find that this header file contains the following header files:


<span style="font-size:16px;">#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> 

These are the header files that must be included to use MFC, and of course we are unlikely to modify these header files in our project, so they are stable.
 
So how do we specify it to generate a precompiled header file. We know that a header file does not compile. So we need one more cpp file to generate the.pch file. This file defaults to StdAfx.cpp. There is only one line of code in this file: #include "Stdafx.h". The reason, of course, is that we just want it to compile, which means we just want its.cpp extension. We can use the /Yc compiler switch to specify StdAfx.cpp to generate a.pch file, and the /Fp compiler switch to specify the name of the generated pch file. Open the project - > Setting- > C/C++ dialog box. Point Category to Precompiled Header. Select the entire project in the tree view on the left, Project Options(the white space in the lower right) to see /Fp "debug/ PCH.pch", which is the name of the generated.pch file, usually by default < Project name > pch. Then, in the tree view on the left, select StdAfx.cpp, and the original Project Option becomes Source File Option (originally a project, now a file, of course changed). Here we can see the /Yc switch, /Yc is used to specify this file to create an Pch file. The file name after /Yc is the header file that contains the stable code, and those that can only have one file per project can have the YC switch. VC compiles StdAfx.cpp into one Obj file and one PCH file according to this option.

So, we've set up the precompiled header file. In other words, we can use the precompiled header function.

Here are some things to note:
 
1) if /Yu is used, that is, precompiled, we include the.h file you specified to produce pch at the beginning of each.cpp file (the default is stdafx.h) otherwise there will be a problem. If you do not include this file, tell you Unexpected file end.
 
2) if you accidentally lose the pch file, based on the above analysis, you only need to ask the compiler to generate one pch file. That is, you just need to recompile stdafx.cpp (the cpp file that specifies /Yc) once.      

Is there such a precompile mechanism on the Linux platform? If so, how does it work? The GCC compiler also implements precompilation on the Linux platform. The project of open source IDE CodeBlocks (CodeBlocks has GCC compiler built in) is taken as an example to illustrate the implementation of Linux platform:
 
Use CodeBlocks to build an C++ project, then create a new my_pch.h, enter the following code:


<span style="font-size:16px;">/*************************************************************** 
 * Name:   my_pch.h 
 * Purpose:  Header to create Pre-Compiled Header (PCH) 
 * Author:   () 

 * Copyright: () 
 * License: 
 *  Method of use :  Project build options --> The other options --> Fill in the next two lines  
 -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> 

Then build options -- in the project > Other options -- > Fill in the next two lines

  -Winvalid-pch
  -include my_pch.h

You can enable precompiled file headers.
Then main.cpp can be compiled without using the include header,


<span style="font-size:16px;">int main() 
{  
using namespace std; 
  cout << "Hello world!" << endl; 
  return 0; 
} 
</span> 

Even if you write the following line in the above code, it doesn't work:


<span style="font-size:16px;">#include <iostream> </span> 

Related articles: