32

In existing code I saw #pragma once be used after header #includes

//Some_Header.h
#include "header1.h"
#include "header2.h"

#pragma once

//implementations

Instead of

//Some_Header.h
#pragma once

#include "header1.h"
#include "header2.h"

//implementations

I thought it always needed to be like the second example, does it matter where your #pragma once is defined or does the preprocessor pick it up anywhere in your file?

Edit

I know #pragma once is not part of the standard and include guards are but that is not my question.

AJM
  • 1,317
  • 2
  • 15
  • 30
turoni
  • 1,345
  • 1
  • 18
  • 37
  • 2
    Do keep in mind that this feature, although widely supported by various compilers, is not a part of standard C++. – Daniel Kamil Kozar Apr 19 '17 at 10:04
  • 2
    I know countless articles about this not being supported everywhere made that I couldn't really find the explanation I wanted. – turoni Apr 19 '17 at 10:05
  • 3
    I never use it, so I wouldn't know for sure - but I'd stick it as close to the beginning of the file as humanly possible. It simply makes more sense. – Daniel Kamil Kozar Apr 19 '17 at 10:06
  • 1
    I always assumed so as well, it being sort of a translation of the include guard but seeing this I wanted to be sure. – turoni Apr 19 '17 at 10:08
  • http://stackoverflow.com/questions/23696115/is-pragma-once-part-of-the-c11-standard as pragma once is not part of c++ standard.Instead of you can use following : #ifndef _DEFINED_ #define _DEFINED_ /* Your code */ #endif – Undefined Behaviour Apr 19 '17 at 10:13
  • 3
    To address the mark for duplication: The other question talks about pragma once position vs include guards. This question talks about pragma once vs header includes. So I think it is incorrectly marked. – turoni Apr 08 '19 at 08:01
  • 2
    This is not a duplicate question and thus shouldn't be marked as such. Questions are unrelated at every level. – Pablo Ariel Sep 24 '20 at 04:45
  • The behavior of `#pragma once` is not standardized (alas) and where it is placed in the file differs in behavior, say, for Visual Studio **CL.EXE** and for LLVM **clang++**. If you want the same behavior for both, put `#pragma once` at the very top, *or* if you also (redundantly?) use header guards, just *after* the header guard, and before anything else (such as the `#include` block). – Eljay Aug 01 '22 at 12:41

3 Answers3

33

#pragma once should be placed before any headers are included. Argument of #pragma directive is a subject to macro expansion. So content of included headers can alter the pragma behavior:

// whatever.hpp
...
#define once lol_no

// your_header.hpp
#include "whatever.hpp"

#pragma once // warning C4068: unknown pragma
user7860670
  • 35,849
  • 4
  • 58
  • 84
  • @user17732522 all `#pragma`s are implementation-defined. – Caleth Aug 05 '22 at 08:48
  • @Caleth I was thinking that macro replacement in the first token after `#pragma` shouldn't happen because `#pragma STDC` is still supposed to work even if `STDC` is defined as a macro, but actually that doesn't matter since C++ does not define `#pragma STDC` and C specifically says that `STDC` is identified before replacement. So yes, there doesn't seem to be any question about standard-conformance. However, it still seems to be MSVC-specific behavior. GCC and Clang do seem to recognize `#pragma once` even if `once` is defined as a macro. – user17732522 Aug 05 '22 at 09:07
9

There isn't really a complete answer on this question covering more than the big 3 compilers, so here's my attempt at a more complete answer.

Summary

  • TL;DR: If you care for portability, put it before any #include or #define statements that may conflict with it (e.g. put it first in the header).
  • Supported by all major compilers ("the big 3" x86_64 compilers as well as intel, and embedded compilers)
  • Placement generally does not matter as long as it reaches the preprocessor (e.g. not blocked by an #if-branch)
  • Different compilers are opinionated on whether it should be first, without documenting what happens if not.
  • Most compilers already detect include guards and treat it as a pragma once anyway, making the benefit largely just not creating a unique guard name.

Below is a quick, summarized guide:

Compiler Support Documentation
Clang Supported GNU-compatible. Not documented, but code shows it as normal preprocessing
GCC Supported gcc pragmas
MSVC Supported (1) MSVC one pragma
Intel (ICC) Supported (1) Intel Compiler Reference Manual - Supported Pragmas
Intel (ICL) Supported (1) ICL uses MSVC front-end
Intel (ICX) Supported ICX is based on Clang
Texas Instruments Supported (2) Reference Manual 5.11.23
Texas Instruments (Clang) Supported This is a fork of Clang with all major features still in effect
ArmCC Supported (3) Compiler Docs for #pragma once

(1) - Supported, but is subject to macro expansion

(2) - Supported, but is documented to be expected at the beginning of the header.

(3) - Supported, but not recommended.

Details

GCC

From the GCC reference manual:

If #pragma once is seen when scanning a header file, that file will never be read again, no matter what. It is a less-portable alternative to using ‘#ifndef’ to guard the contents of header files against multiple inclusions.

(emphasis mine)

Scanning is done at preprocessing time, and so as long as the #pragma statement is visible to the preprocessor (not in an unreachable conditional block from #if), then it will take effect.

GCC's #pragma once is not affected by preprocessor substitution.

Live Example

Clang

Clang's reference manual doesn't actually specify #pragma once so far as I can tell, however Clang is meant to be compatible with most, if not all, GCC builtins and features.

Viewing the source code for Clang's preprocessor phase indicates what you would expect; it handles #pragma once during preprocessing (source)

 void Preprocessor::HandlePragmaOnce(Token &OnceTok) {
   ...
   // Mark the file as a once-only file now.
   HeaderInfo.MarkFileIncludeOnce(getCurrentFileLexer()->getFileEntry());
 }

Like GCC, the placement of the #pragma once does not matter if it's first, and is not affected by preprocessor substitution.

Live Example

MSVC

MSVC's documentation on #pragma once does not indicate where it belongs, just that it should be in a source (and has an example of it at the top).

As mentioned by others, when using #pragma once in MSVC, it is subject to preprocessor-expansion.

With Substitution

Live Example

Without Substitution

Live Example

Intel (CL-Based)

When using the Intel compiler on Windows, the compiler uses an MSVC Compatibility mode (ICL). Although it's not documented in the Supported Pragma, though it does appear to be supported. The placement does not appear to matter as well so long as the preprocessor reaches it.

ICL's #pragma once is subject to the preprocessor-expansion issue that MSVC experiences.


Note: icl is not supported on compiler-explorer, so no example is available.

Intel (GNU-Based)

When using the Intel compiler on Linux or older macOS versions (ICC), the compiler uses a GNU compatibility mode.

Like above, it's not explicitly listed as a Supported Pragma, though it does appear to be supported in practice. The placement does not appear to matter as well so long as the preprocessor reaches it.

ICC's #pragma once is subject to the preprocessor-expansion issue that MSVC experiences.

With Substitution

Live Example

Without Substitution

Live Example

Intel (Clang-Based)

The newer Intel ICX NextGen compiler is based off of Clang / LLVM technology. Behaviourally, this matches what Clang does.

Unlike other Intel compilers, but like Clang, thisdoes not suffer from the preprocessor-expansion issue.

Live Example

Arm (armcc)

The armcc compiler advises against #pragma once, but does also provide an example of it existing after #define statements as an optional feature to work with inclusion guards.

Given the example, placement should likely not be an issue.

It's unclear where this will experience any preprocessor expansion.


Note: armcc is not supported on compiler-explorer, so no example is available.

Texas Instruments (TI ArmCL)

As mentioned in the reference manual, section 5.11.23:

This pragma should be used at the beginning of a header file that should only be included once. For example:

// hdr.h
#pragma once
#warn You will only see this message one time
struct foo
{
  int member;
};

(Emphasis mine)

I haven't tested what happens if it's moved anywhere lower than the comment header, but the compiler only officially supports it at the beginning of the file.

I would suspect this should not matter, but cannot confirm.

It's unclear where this will experience any preprocessor expansion.


Note: tiarmcl (and other similar ti compilers) are not supported on compiler-explorer, so no example is available.

Texas Instruments (tiarmclang)

This is a fork of clang, so it behaves the same as clang does.

The #pragma once in this implementation can be effectively placed anywhere the preprocessor reaches, and does not deal with preprocessor substitution.


Note: tiarmclang is not supported on compiler-explorer, so no example is available.

Human-Compiler
  • 11,022
  • 1
  • 32
  • 59
7

#pragma once relates only to a file where it is placed. It matters to the compiler whether the file contains this pragma or not, and the position of it is unimportant. Therefore, the line with #pragma once can be placed anywhere in the file except for chunk of code that is excluded from compilation by the conditional preprocessor directives like #if, #ifdef and #ifndef. The excluded chunk of code is not parsed by the compiler and if it contains the preprocessor directive it has no effect.

Despite the fact that #pragma once can be placed at any line that is parsed by the compiler, I strongly recommend to follow the common practice and put #pragma once at the beginning of a header file.

Also, as @user7860670 mentioned, arguments of #pragma directive is a subject to macro expansion for MSVC compiler. But neither gcc nor clang support it:

Egor
  • 485
  • 4
  • 8
  • 1
    _"It matters to the compiler whether the file contains this pragma or not, and the position of it is unimportant"_ This is not quite true. The `#pragma once` directive has to actually have been _reached_ by the compiler. if it hides behind an `#if` branch that isn't taken, then it doesn't take effect: https://godbolt.org/z/j3jecEd6v – Human-Compiler Aug 04 '22 at 18:10
  • You are right. If the block of code is excluded from compilation, it is not parsed by the compiler and if this block contains the preprocessor directive, it has no effect. I've updated the answer, thank you for your input. – Egor Aug 05 '22 at 08:15