cconstexprc23

error: constexpr pointer initializer is not null


I have this very simple program:

int main(void)
{
    static constexpr const char *const str = "hello";
}

which fails to compile with this error:

$ gcc -std=c2x str.c
str.c: In function 'main':
str.c:6:46: error: 'constexpr' pointer initializer is not null
    6 |     static constexpr const char *const str = "hello";
      |                                              ^~~~~~~

$ gcc -v
...
gcc version 13.1.0 (MinGW-W64 x86_64-ucrt-posix-seh, built by Brecht Sanders)

Why is nullptr the only pointer type allowed to be constexpr?


Solution

  • The C23 standard explicitly states that pointers declared as constexpr must be null-initialized, as per section section 6.7.1p5:

    An object declared with storage-class specifier constexpr or any of its members, even recursively, shall not have an atomic type, or a variably modified type, or a type that is volatile or restrict qualified. The declaration shall be a definition and shall have an initializer141). The value of any constant expressions or of any character in a string literal of the initializer shall be exactly representable in the corresponding target type; no change of value shall be applied142). If an object or subobject declared with storage-class specifier constexpr has pointer, integer, or arithmetic type, the implicit or explicit initializer value for it shall be a null pointer constant143), an integer constant expression, or an arithmetic constant expression, respectively.

    1. The named constant or compound literal constant corresponding to an object declared with storage-class specifier constexpr and pointer type is a constant expression with a value null, and thus a null pointer and an address constant. However, even if it has type void * it is not a null pointer constant.

    The reason that only null pointers can be used to initialize a constexp pointer is because the value of a constexp must be known at translation time, i.e. when the code is parsed. This is explained in section 6.7.1p11:

    An object declared with a storage-class specifier constexpr has its value permanently fixed at translation-time; if not yet present, a const-qualification is implicitly added to the object’s type. The declared identifier is considered a constant expression of the respective kind, see ??.

    This means that address constants, such as the start address of a string literal, which aren't known until the code is actually compiled, can't be used for constexp pointers.

    Arguably, address constants should be allowed to initialized constexp pointers.