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
?
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 isvolatile
orrestrict
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 specifierconstexpr
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.
- 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 typevoid *
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.