📜 ⬆️ ⬇️

For beginners about stdafx.h

StdAfx.h, Precompiled headers
The article is intended for people who are familiar with the Visual Studio environment and try to compile their C ++ projects in it. In an unfamiliar environment, everything seems strange and incomprehensible. Especially novice annoying stdafx.h file, because of which there are strange errors during compilation. Very often it all ends with the fact that a newbie for a long time everywhere carefully turns off Precompiled Headers. To help people figure out what was happening, this article was written.

What are Precompiled Headers for?


Precompiled headers are designed to speed up the build of projects. Usually, programmers start to get familiar with Visual C ++ using tiny projects. It is difficult to notice the gain from precompiled headers on them. What happens to them, that without them, the program compiles the same time. This adds confusion. The person does not see the benefit of this mechanism for himself and decides that he is for specific tasks and he will never need it. And sometimes he thinks so for many years.

In fact, precompiled headers is a very useful technology. The benefit from it can be seen, even if the project has only a few dozen files. Especially the gain becomes noticeable if such heavy libraries as boost are used.

If you look at the * .cpp files in the project, you will notice that many include the same sets of header files. For example, <vector>, <string>, <algorithm>. In turn, these files include other header files and so on.
')
All this leads to the fact that the preprocessor in the compiler again and again performs the same work. It must read the same files, insert them into each other, select the #ifdef branches and substitute the values ​​of the macros. There is a tremendous duplication of the same operations.

You can significantly reduce the amount of work that the preprocessor must do when compiling a project. The idea is to preprocess a group of files in advance and then simply substitute a ready-made piece of text.

In fact, a number of steps are being taken. You can store not just text, but more processed information. I don't know how exactly Visual C ++ works. But, for example, you can store the text already broken into lexemes. This will further speed up the compilation process.

How Precompiled Headers Work


The file that contains the precompiled headers has the extension ".pch". The file name is usually the same as the project name. Naturally, this and other used names can be changed in the settings. A file can be quite large and depends on how many header files it contains. For example, in the PVS-Studio project, it takes about 3 megabytes.

The * .pch file occurs after compiling stdafx.cpp. The file is collected with the "/ Yc" key. This key just tells the compiler to create precompiled headers. The stdafx.cpp file can contain one line: #include "stdafx.h".

The file "stdafx.h" is the most interesting. Here you need to include header files that will be preprocessed in advance. As an example, here is the stdafx.h file that we use in PVS-Studio (the file is abbreviated for the article):
#include "VivaCore/VivaPortSupport.h" //For /Wall #pragma warning(push) #pragma warning(disable : 4820) #pragma warning(disable : 4619) #pragma warning(disable : 4548) #pragma warning(disable : 4668) #pragma warning(disable : 4365) #pragma warning(disable : 4710) #pragma warning(disable : 4371) #pragma warning(disable : 4826) #pragma warning(disable : 4061) #pragma warning(disable : 4640) #include <stdio.h> #include <string> #include <vector> #include <iostream> #include <fstream> #include <algorithm> #include <set> #include <map> #include <list> #include <deque> #include <memory> #pragma warning(pop) //For /Wall 

Directives "#pragma warning" we need to get rid of the warnings issued to the standard library.

Now in all files * .c / *. Cpp should include "stdafx.h". At the same time it is worth removing from these files the headers that are already included with the help of "stdafx.h".

And what if there are used though similar, but different sets of header files? For example, such:Need to do separate precompiled headers? So you can do, but not necessary.

It is enough to make one precompiled header in which <vector>, <string> and <algorithm> will be opened. The gain is due to the fact that during preprocessing it is not necessary to read a lot of files and insert them into each other much more than the losses on the syntax analysis of unnecessary code fragments.

How to use Precompiled Headers


When creating a new Wizard project in Visual Studio, it creates two files: stdafx.h and stdafx.cpp. It is through them that the precompiled headers mechanism is implemented.

In fact, these files can be called as you like. It is important not the name, but the compilation parameters in the project settings.

In the * .c / *. Cpp file you can use only one precompiled header. However, there may be several different precompiled headers in the same project. For now, we’ll assume that we have only one.

So, if you use the wizard, then you already have the files stdafx.h and stdafx.cpp. Plus exhibited all the necessary compilation keys.

If the project did not use the precompiled headers mechanism, then let's consider how to enable it. I suggest the following sequence of actions:
  1. In all configurations for all * .c / *. Cpp files we enable the use of precompiled headers. This is done on the Precompiled Header tab:
    1. Set the value for "Precompiled Header" to "Use (/ Yu)".
    2. For the “Precompiled Header File” parameter, specify “stdafx.h”.
    3. For the "Precompiled Header Output File" parameter, specify "$ (IntDir) $ (TargetName) .pch".
  2. Create and add the stdafx.h file to the project. In the future, we will include in it those header files that we want to preprocess in advance.
  3. Create and add the stdafx.cpp file to the project. It has one single line: #include "stdafx.h".
  4. In all configurations, we change the settings for the stdafx.cpp file. Set the “Precompiled Header” value to “Create (/ Yc)”.
So we turned on the precompiled headers mechanism. Now, if we run the compilation, a * .pch file will be created. However, then the compilation will stop due to errors.

For all * .c / *. Cpp files, we indicated that they should use precompiled headers. This is not enough. Now in each of the files you need to add #include "stdafx.h".

The header file "stdafx.h" should be included in the first * .c / *. Cpp file. Sure to! Otherwise, compilation errors will still occur.

If you think about it, there is logic. When the file “stdafx.h” is at the very beginning, you can substitute already preprocessed text. This text is always the same and does not depend on anything.

Imagine the situation if we could include another file before “stdafx.h”. And in this file, take and write: # define bool char. There is an ambiguity. We change the contents of all files that mention "bool". Now you just can not take and substitute a preprocessed text. The whole mechanism of "precompiled headers" is breaking. I think this is one of the reasons why “stdafx.h” should be located at the beginning. Perhaps there are others.

Life hack


Writing #include "stdafx.h" into all * .c / *. Cpp files is quite tiresome and not interesting. Additionally, you will get a revision in the version control system, where a huge number of files will be changed. Not good.

Another inconvenience is caused by third-party libraries that are included in the project as files with code. Edit these files is not washed away. For the right, they need to disable the use of "precompiled headers". However, if several small third-party libraries are used, this is inconvenient. The programmer constantly stumbles on precompiled headers.

There is an option how to use precompiled headers is easy and simple. The method does not fit everywhere and always, but he often helped me.

You can not add to all #include “stdafx.h” files, but use the “Forced Included File” mechanism.

Go to the settings tab «Advanced». Select all configurations. In the field "Forced Included File" we write:

StdAfx.h;% (ForcedIncludeFiles)

Now "stdafx.h" will automatically be included in the beginning of ALL compiled files. PROFIT!

You no longer need to write #include "stdafx.h" at the beginning of all * .c / *. Cpp files. The compiler will do it himself.

What to include in stdafx.h


This is a very important point. Thoughtless inclusion in the “stdafx.h” just in a row will not only not speed up the compilation, but, on the contrary, slow it down.

All files that include "stdafx.h" depend on its content. Suppose that the file "Xh" is included in "stdafx.h". If you change at least something in "Xh", this may entail a complete recompilation of the entire project.

Rule Include in stdafx.h only those files that never change or change VERY rarely. Good candidates are system header files and third-party libraries.

If you include your own files from the project in “stdafx.h”, keep double vigilance. Include only those files that change very, very rarely.

If any * .h file changes once a month, it is too often. As a rule, it is rarely possible to make all edits in the h-file the first time. It usually takes 2-3 iterations. Agree, 2-3 times to completely recompile the entire project is an unpleasant task. Plus full recompilation is required for all your colleagues.

Do not get carried away with unchangeable files. Include only what is often used. It makes no sense to include <set> if it is needed only in two places. Where necessary, there connect this header file.

Multiple Precompiled Headers


Why in one project may need several precompiled headers? Indeed, this is not necessary often. But I will give a couple of examples.

In the project, * .c and * .cpp files are used simultaneously. For them, you can not use a single * .pch file. The compiler will generate an error.

You need to create two * .pch files. One should be obtained when compiling the C-file (xx.c), and the other when compiling the C ++ file (yy.cpp). Accordingly, it is necessary to specify in the settings that one precompiled header is used in the C-files, and another one is used in the C ++ files.

Note. Do not forget to specify different names for * .pch files. Otherwise, one file will grind another.

Another situation. One part of the project uses one large library, and the other part uses another large library.

Naturally, it is not worth all parts of the code to know about both libraries. In (unsuccessful) libraries, the names of some entities may overlap.

It is logical to make two precompiled headers and use them in different parts of the program. As already noted, you can specify arbitrary file names from which * .pch files are generated. And the name of the * .pch file can also be changed. All this, of course, needs to be done carefully, but there is nothing difficult to use the two precompiled headers.

Typical errors when using Precompiled Headers


After reading carefully the material above, you can understand and eliminate errors related to stdafx.h. But let's go through the compilation type errors again and analyze their causes. Repetition is the mother of learning.

Fatal error C1083: Cannot open precompiled header file: 'Debug \ project.pch': No such file or directory


You are trying to compile a file that uses a precompiled header. But the corresponding * .pch file is missing. Possible reasons:
  1. The stdafx.cpp file was not compiled and, as a result, the * .pch file has not yet been created. This may be, for example, if you clean the project at the beginning (Clean Solution), and then try to compile one * .cpp file (Compile Ctrl-F7). Solution: compile the whole project or at least the stdafx.cpp file.
  2. In the settings there is not a single file from which the * .pch file should be generated. This is a compilation key / Yc. As a rule, this situation occurs in beginners who want to use precompiled headers for their project. How to do this is described above in the "How to use Precompiled Headers" section.

Fatal error C1010: while looking for a precompiled header. Did you forget to add '#include "stdafx.h"' to your source?


The message speaks for itself if you read it. The file is compiled with the / Yu. This means that you should use the precompiled header. But “stdafx.h” is not included in the file.

It is necessary to enter in the file #include "stdafx.h".

If this is not possible, then you should not use the precompiled header for this * .c / *. Cpp file. Remove the key / Yu.

Fatal error C1853: 'comp.pch' precompiled header of the compiler, or the precompiled header of the compiler


There are both C (* .c) and C ++ (* .cpp) files in the project. For them, you cannot use a single precompiled header (* .pch file).

Possible solutions:
  1. Disable precompiled headers for all C-files. As practice shows, * .c files are preprocessing several times faster than * .cpp files. If * .c files are not very many, then by disabling the precompiled headers for them, you will not lose anything
  2. Start two precompiled headers. The first should be created from stdafx_cpp.cpp, stdafx_cpp.h. The second of stdafx_c.c, stdafx_c.h. Accordingly, different precompiled headers should be used in * .c and * .cpp files. The names of the * .pch files naturally should also be different.

Due to the precompiled header the compiler is buggy


Most likely, something is done wrong. For example, #include "stdafx.h" is not located at the very beginning.

Consider an example:
 int A = 10; #include "stdafx.h" int _tmain(int argc, _TCHAR* argv[]) { return A; } 

This code will not compile. At first glance, the compiler will generate a strange error message:
 error C2065: 'A' : undeclared identifier 

The compiler thinks that everything up to the line #include "stdafx.h" (inclusive) is the precompiled header. When compiling a file, the compiler will replace everything before #include "stdafx.h" with text from the * .pch file. As a result, the line “int A = 10” is lost.

The correct option is:
 #include "stdafx.h" int A = 10; int _tmain(int argc, _TCHAR* argv[]) { return A; } 

Another example:
 #include "my.h" #include "stdafx.h" 

The contents of the file "my.h" will not be used. As a result, you will not be able to use the functions declared in this file. This behavior is very confusing for programmers. They “cure” it by completely disabling the precompiled headers and then telling stories about the glitchiness of Visual C ++. Remember, the compiler is one of the most rarely buggy tools. In 99.99% of cases, one should not get angry at the compiler, but look for the error in oneself ( Proof ).

To avoid such situations, ALWAYS write #include "stdafx.h" at the very beginning of the file. Comments before #include "stdafx.h" can be left. They still do not participate in the compilation.

Another option is to use Forced Included File. See the “Life hack” section above.

Because of the precompiled headers, the project is constantly recompiled entirely.


A stdafx.h file is included that is regularly edited. Or accidentally included auto-generated file.

Carefully check the contents of the stdafx.h file. It should include only header files that do not change or change very rarely. Note that the included files may not change, but inside they refer to other variable * .h files.

Something incomprehensible going on


Sometimes it may be a situation that you have corrected the code, but the error does not disappear. The debugger shows incomprehensible things.

The reason may be a * .pch file. Somehow it happened that the compiler does not notice the changes in one of the header files and does not rebuild the * .pch file. As a result, the old code is substituted. Perhaps this was due to some failures related to the time of file modification.

This is a VERY rare situation. But it is possible and you need to know about it. For many years of programming, I have come across it only 2-3 times. The complete recompilation of the project helps.

The project using precompiled headers cannot be verified with PVS-Studio


This is the most common situation with which we are approached in support. Details are given in the documentation: " Troubleshooting during PVS-Studio work ". Here I will describe the situation briefly.

If the solution is compiled, it does not mean that it is properly organized. Often, one solution contains many projects. Each project uses its own precompiled headers (there is its own stdafx.h and stdafx.cpp).

Problems arise when they start using files from a nearby project. It is convenient and so often done. They just forget that it is written in the * .cpp file: #include "stdafx.h".

And which stdafx.h picks up is an interesting question. But once the program is compiled - the programmer is lucky.

Unfortunately, it is difficult for us to repeat the behavior that occurs when using the * .pch file. An “honest” preprocessor works differently.

The fact that the solution, in fact, does not work correctly, can be seen by temporarily disabling the precompiled headers. A lot of interesting errors can come out right away, and the programmer will be genuinely surprised at how miraculously his project was compiled.

For details, I again refer to the documentation. Plus, if something is still not clear, we will show in support.

Conclusion


As you saw, there is nothing difficult in precompiled headers. All the “numerous compiler glitches” that a programmer encounters when using them are, in fact, a lack of understanding of the principles of operation. I hope this article will help eliminate misunderstanding.

Precompiled headers are a very useful mechanism to significantly increase the speed of compiling projects.

Source: https://habr.com/ru/post/227521/


All Articles