Precompiled Headers & Normal C++ Semantics

If arranged correctly, precompiled headers, like those in Visual C++, can double the build speed. However, it is possible also to arrange precompiled header files in a manner that is inconsistent with normal C++ semantics.


October 01, 2001
URL:http://www.drdobbs.com/cpp/precompiled-headers-normal-c-semantics/184404800

Oct01: Precompiled Headers & Normal C++ Semantics

Jeffrey is a C++ consultant who can be contacted at [email protected].


To reduce the amount of time required to build a project, Microsoft's Visual C++ supports precompiled headers. When a header file is included by many C++ files in a project, the header file may be added to the precompiled header and compiled only once for the entire project, rather than once for every C++ file in that project. I have seen the use of precompiled headers halve the build time. Of course, each project will have unique characteristics, and the level of improvement may vary.

However, it is possible to arrange pre-compiled header files in a manner that is inconsistent with normal C++ semantics. Sun compilers, for instance, do not support precompiled headers. Nevertheless, when code is structured properly, precompiled headers can be used with Visual C++ and still be compatible with Sun's compilers.

On Solaris, for instance, Example 1 prints "James Brown." While you might guess that when using the precompiled headers in Visual C++, the program would print "Charlie Daniels," in fact, it instead prints "Charlie Brown." This command line creates a precompiled header when using Visual C++:

cl /c /Ycpch.h pch.cpp

The /Yc option instructs Visual C++ to create a precompiled header, checkpointing the compilation state after pch.h is processed. In Example 1, the precompiled data is kept in a file called "pch.pch" and includes the definition of STR1 and all of iostream.h. Compilation continues after pch.h is processed, but later data is not written to pch.pch. In this example, the definition of STR2 is not included in pch.pch.

The precompiled header data may be used with the following command:

cl /Yupch.h main.cpp

The /Yu option instructs Visual C++ that the source file will attempt to include pch.h. When the include statement is processed, the compiler uses the precompiled data in pch.pch rather than processing pch.h. In Example 1, STR1 is defined as "Charlie" in the precompiled header. STR2 is defined as "Brown" from main.cpp. "Charlie Brown" is printed.

Within the Microsoft development environment, Visual C++ precompiled header specifications for a project can be viewed by pressing Project, Settings, the C/C++ tab, and finally, the category Precompiled Headers.

Typically, one C++ file in the project is set to "Create precompiled header file (.pch) through header <some_filename.h>." This is the first file built for the project. When the debug configuration is built, the data from the compilation of this file, up to and including "<some_filename.h>," is placed in a file named "WinDebug/your_project_name.pch."

Most files will be set to "Use precompiled header file (.pch) through header: <some_filename.h>." This tells Visual C++ that when it parses #include <some_filename.h>, it should disregard "some_filename.h" and insert the precompiled header.

To ensure compatibility, do not put anything in pch.cpp, except #include <pch.h>. As in Example 2, move the definitions of STR1 and STR2 into pch.h using this approach. The performance benefits from the use of precompiled headers is not diminished, the code is easier to read, and the results are consistent with normal C++ semantics.

I was not able to find any documentation from Microsoft that specifically recommends the structure for precompiled header files. However, the comments that Visual C++ inserts into AppWizard projects are consistent with my approach. When Microsoft Visual C++ 6.0 creates a new Win32 Application project (A typical "Hello World" application), it creates a file called "stdafx.h" with the following text:

// stdafx.h : include file for standard system // include files,

// TODO: reference additional headers your // program requires here

It creates a file, "stdafx.cpp," with the text:

// stdafx.cpp : source file that includes just // the standard includes

#include "stdafx.h"

// TODO: reference any additional headers // you need in STDAFX.H

// and not in this file

Clearly, my approach is consistent with Microsoft's architecture, yet still enables compatibility with Solaris.

DDJ

Oct01: Precompiled Headers & Normal C++ Semantics

(a) pch.h
// Solaris JUST includes this file.
#include 

(b) pch,cpp
// Visual C++ puts the start of this file into the
//				      precompiled header.
#define STR1 "Charlie "
#include "pch.h"
#define STR2 "Daniels"

(c) main.cpp
#include "pch.h"

#ifndef STR1
#  define STR1 "James "
#endif

#ifndef STR2
#  define STR2 "Brown"
#endif

int main()
{
    cout << STR1;
    cout << STR2;
    return 0;
}

Example 1: This program has different behaviors on NT and UNIX: (a) pch.h; (b) pch.cpp; (c) main.cpp.

Oct01: Precompiled Headers & Normal C++ Semantics


(a) pch.h
// Sun Forte C++: The contents of this file will be
//           included through normal C++ semantics.
// MS Visual C++: The contents of this file will be 
//           included through the precompiled header.
#include <iostream.h>
#define STR1 "James "
#define STR2 "Brown"

(b) pch.cpp
// Do add anything to this file!
// Any additional code should be placed in pch.h.
#include "pch.h"

(c) main.cpp
#include "pch.h"

int main()
{
	cout << STR1;
	cout << STR2;
	return 0;
}

Example 2: This C++ program has the same behavior on NT and UNIX: (a) pch.h; (b) pch.cpp; (c) main.cpp.

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.