#once
C Document number: N2896
Date: 2021-12-27
Author: Miguel Ojeda <ojeda@ojeda.dev>
Project: ISO/IEC JTC1/SC22/WG14: Programming Language C
This proposal adds a standard version of the #pragma once
feature implemented in major compilers.
#once
.The #pragma once
feature is provided by compilers as a more ergonomic include guard, i.e. instead of writing a header like:
/*
* Some header.
*/
#ifndef SOME_HEADER_H
#define SOME_HEADER_H
// File contents
#endif // SOME_HEADER_H
Users may write it like:
/*
* Some header.
*/
#pragma once
// File contents
The feature is supported in all major compilers:
However, the semantics of “having seen a file” can be unclear (e.g. is it based on the path? On the inode? On the contents?) and unreliable (e.g. filesystem aliasing), thus some projects like the Linux kernel prefer to avoid using #pragma once
, though they may use such a feature if it allows to provide an identifier [1].
This proposal adds a new preprocessing directive, #once
, as a standard and shorter version of #pragma once
, in two variants.
The first variant has implementation-defined semantics and the intention is that translators that already provide #pragma once
give it the same semantics (and document them):
/*
* Some header.
*/
#once
// File contents
The benefits of this variant with respect to #pragma once
is that it is standard and shorter.
The second variant, which takes an identifier, is a replacement for an explicit include guard for projects that do not wish to rely on the interpretation of “having seen a file” that their compilers may do:
/*
* Some header.
*/
#once SOME_HEADER_H
// File contents
The benefits of this variant with respect to an explicit include guard is that it is standard, shorter and avoids duplicating the identifier (twice if the project uses the fairly common convention of writing it also in the #endif
directive as a comment).
Both variants are required to come before any other preprocessor directive, but may come after text lines (typically, comments such as a top-level description of the header or a SPDX [2] line). Only a single #once
directive is allowed per source file (though more may appear in the preprocessing translation unit).
The proposed wording is with respect to the N2596 C2x Working Draft.
In “4. Conformance”, after paragraph 4 add a new one:
The implementation shall not successfully translate a source file where, after translation phase 3, preprocessing tokens appear before a
#once
preprocessing directive.
In “6.10 Preprocessing directives”, modify paragraph 1 to add the #once
directive after #error
and before #pragma
:
…
control-line:
…
#
error
pp-tokensopt new-line
#
once
new-line
#
once
identifier new-line
#
pragma
pp-tokensopt new-line…
Before “6.10.1 Conditional inclusion”, add a new section:
6.10.1 Once directive
Constraints
After translation phase 3, preprocessing tokens shall not appear before a
#once
preprocessing directive. (Footnote 1) (Footnote 2)(Footnote 1) Sequences of white-space characters (including comments) may appear.
(Footnote 2) This implies that a
#once
preprocessing directive shall be the first in a source file. It also implies that there cannot be more than one#once
preprocessing directive in a source file. Finally, it implies that#once
cannot appear as part of a skipped group.Semantics
A preprocessing directive of the form
#
once
new-linecauses the implementation to behave in an implementation-defined manner.
A preprocessing directive of the form
#
once
identifier new-linecauses the implementation to behave as if the source file was prefixed with
#ifndef
identifier
#define
identifierand suffixed with
#endif
In “J.3.11 Preprocessing directives”, add a new entry:
The behavior of a
#once
preprocessing directive when no identifier is given (6.10.1).
Thanks to Joseph Myers for reviewing and providing suggestions.