#once

C Document number: N2742
Date: 2021-10-17
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.

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 C23 Working Draft.

In “4. Conformance”, after paragraph 4 add a new one:

The implementation shall not successfully translate a source file containing more than one #once preprocessing directive or containing one if it is not the first preprocessing directive in the source file.

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

After “6.10.5 Error directive”, add a new section:

6.10.6 Once directive

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

If more than one #once directive appears in the source file, or if a preprocessing directive appears before it, then this causes the implementation to produce a diagnostic message.

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