#once

C Document number: N2896
Date: 2021-12-27
Author: Miguel Ojeda <[email protected]>
Project: ISO/IEC JTC1/SC22/WG14: Programming Language C

Abstract

This proposal adds a standard version of the #pragma once feature implemented in major compilers.

Changelog

N2896

Introduction

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).

Wording

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-line

causes the implementation to behave in an implementation-defined manner.

A preprocessing directive of the form

            # once identifier new-line

causes the implementation to behave as if the source file was prefixed with

            #ifndef identifier
            #define identifier

and 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).

Acknowledgements

Thanks to Joseph Myers for reviewing and providing suggestions.

References

  1. LKML: [PATCH 00/11] pragma once: treewide conversion — https://lore.kernel.org/lkml/CAHk-=wgTWnAZitAYrSD508rxoLtB47p1ntyqYLzVeb=mTQ6tHw@mail.gmail.com/
  2. Software Package Data Exchange — https://spdx.dev