How C++ compiler works for header guards and include guards

Hi Friends,
I am new to C++ programming(I know the concepts but I don't have programming experience).
I was doing some C++ coding. While coding, some questions came across my mind which I wanted to make clear from you. Below are those?

1) How compiler works for #pragma once and #ifndef in header files? I mean for next time how it will identify that it doesn't have to include this file?
2) Which is better to use, #pragma once or #ifndef and why?
3) Is there any name for #pragma once? Like for #ifndef we use include guard or header guard in the same way is there any name for #pragma once?

Thanks
~Sandy
1) How compiler works for #pragma once and #ifndef in header files? I mean for next time how it will identify that it doesn't have to include this file?
1
2
3
4
5
6
#ifndef FILE_H
#define FILE_H

// file content

#endif 

The #ifndef checks if FILE_H has not been defined. If it's the first time the file is included it will not be defined (assuming no other file defines FILE_H) so it will carry on with the code between the #ifndef and the #endif. The #define defines the FILE_H macro so next time the file is included the #ifndef check will fail and so the content between the #ifndef and the #endif will be skipped.

2) Which is better to use, #pragma once or #ifndef and why?

#pragma once is non-standard (but widely supported). It doesn't really matter which one you use but I prefer using #ifndef because it's standard C++ and therefore guaranteed to work with all C++ compilers.

3) Is there any name for #pragma once? Like for #ifndef we use include guard or header guard in the same way is there any name for #pragma once?

Both are include guards. It's just two different ways to accomplish the same thing.

Note that #ifndef in itself is not an include guard. There are other uses for #ifndef besides include guards. It's when you use it together with #define and #endif in a header to prevent the file content from being included more than once that it becomes an include guard.
Last edited on
closed account (z05DSL3A)
There is a slight difference between #pragma once and #ifndef in header files.

#pragma once will process the header file once, the next time an #include for the same file is met in the code it is ignored. With #ifndef the file is still opened and processed even is most of its contents are ignored.


1
2
3
4
5
6
7
8
9
10
//#pragma once

#ifndef HEADER_H
#define HEADER_H

#pragma message("Processing header.h") 

#endif 

#pragma message("Finished processing header.h")  
header.h

1
2
3
4
5
6
7
#include"header.h"
#include"header.h"

int main()
{

}
main.cpp

With the #pragma once commented out in the above you would see compiler messages like
1>  Processing header.h
1>  Finished processing header.h
1>  Finished processing header.h
showing that it has processed the file twice. uncommenting the #pragma once (and if your compiler supports it) you would see
1>  Processing header.h
1>  Finished processing header.h
showing that it has totally ignored the second #include.

The use of #pragma once could improve build times in large projects.
To add to the Grey Wolf message:

When using #pragma once, use it alongside header guards, not instead of them. Or you can have loads of fun finding the problem when you happens to have same file in two different places under different names.
MiiNiPaa+1

1
2
3
4
5
#pragma once
#ifndef MY_QUUX_HPP
#define MY_QUUX_HPP

...

http://www.cplusplus.com/faq/beginners/multiple-sources/#header
Last edited on
> #pragma once will process the header file once,
> the next time an #include for the same file is met in the code it is ignored.
> With #ifndef the file is still opened and processed even is most of its contents are ignored.

Mainstream tool chains implement the 'Multiple-Include Optimization'.
Header files are often of the form
1
2
3
4
     #ifndef FOO
     #define FOO
     ...
     #endif 

to prevent the compiler from processing them more than once. The preprocessor notices such header files, so that if the header file appears in a subsequent #include directive and FOO is defined, then it is ignored and it doesn't preprocess or even re-open the file a second time. This is referred to as the multiple include optimization.
- https://gcc.gnu.org/onlinedocs/cppinternals/Guard-Macros.html

IIRC, GCC has had it since version 3.4

The example posted prevents this optimisation; while #pragma once applies to the entire contents of the header, the conforming include guard guards only a portion of the header.
If the file were included a second time, it can only be optimized away if that inclusion would result in no tokens to return, and no relevant directives to process.
...
There must be no tokens outside the controlling #if-#endif pair, but whitespace and comments are permitted.
There must be no directives outside the controlling directive pair, but the null directive (a line containing nothing other than a single ‘#’ and possibly whitespace) is permitted.
...
The example posted prevents this optimisation;

The multiple include optimization (adding the file name to the compiler's list of 'already processed' files) is specifically invoked via the #pragma directive, and in the case of the GCC, the #ifndef also.

The no-token requirement exists to guarantee that the #ifndef functions at the same scope as the #pragma directive.

That is, they both do the same thing, and elicit the same behavior from the GCC. So unless the GCC people have taken effort to do something weird to break that (and I wouldn't put it past them, honestly), then the example posted above behaves identically for not just the GCC, but all compilers that implement MIO. (It should perform identically for the GCC as well. But even if it doesn't, any performance drop is miniscule compared to actually opening a file and reading the first few tokens.)

The posted example covers every standard-conforming compiler in existence, not just the GCC, where the only noticeable performance problems are in compilers that don't actually perform MIO.
Simple multiple-include optimization (with the #ifndef construct) is easy to implement with just a few lines of code; every current C++ implementation has it in some form or other.
For instance: http://clang.llvm.org/doxygen/MultipleIncludeOpt_8h_source.html

For two reasons, this discussion is largely academic.

Modern operating systems aggressively cache repeatedly used files; the cost of opening a cached file is negligible in comparison to the cost of lexing it.

For very large code-bases with deeply nested header files, the OS may not be able cache all the header files and the number of file-opens (without mio) would be very high. However, such projects tend to use pre-compiled headers.

Note: There was a proposal to make #pragma once part of the standard. It was discarded because of the difficulty in efficiently surmounting practical problems in its implementation. (The same file may be accessed through many, superficially unrelated, paths: multiple hard and soft links, multiple mounts of network file systems).
Topic archived. No new replies allowed.