Latest gcc 13.x (trunk) gives a compiler error (gcc -std=c23
) for this code:
int* p = false;
error: incompatible types when initializing type '
int *
' using type '_Bool
'
How can this be correct?
C23 6.2.5 §8-9 (Types - the definition of integer types):
The type
bool
and the unsigned integer types that correspond to the standard signed integer types are the standard unsigned integer types.The standard signed integer types and standard unsigned integer types are collectively called the standard integer types;
C23 6.6 §8 (Constant expressions - the definition of an integer constant expression):
An integer constant expression shall have integer type...
C23 6.3.2.3 (Pointers - the definition of null pointer constant)
An integer constant expression with the value 0, such an expression cast to type
void *
, or the predefined constantnullptr
is called a null pointer constant
C23 6.5.16.1 (Simple assignment):
Constraints
/--/
- the left operand is an atomic, qualified, or unqualified pointer, and the right operand is a null pointer constant
Conclusion:
int* p = false;
is a valid form of assignment,false
is a null pointer constant,bool
, which is one of the standard integer types.Did I misunderstand anything in the standard or is this a gcc bug? clang gives a warning but still produces an executable. I don't really see how any of the above has changed in C23 either.
Including stdbool.h
and compiling under gcc -std=c17 -pedantic-errors
makes it compile cleanly as expected.
In addition to the paragraphs quoted in the question, there is paragraph 6.4.4.5/3:
The keywords
false
andtrue
are constants of typebool
with a value of 0 forfalse
and 1 fortrue
.
and 6.6/7:
An identifier that is:
[...]
— a predefined constant;
[...]
is a named constant
That makes false
a named constant, which is relevant because a fuller quotation of 6.6/8 is
An integer constant expression shall have integer type and shall only have operands that are integer constants, named and compound literal constants of integer type [...]
(emphasis added).
Regardless, then, of GCC implementation details surrounding the constant false
, when taken as an expression, false
meets C23's criteria for an integer constant expression. Its value is specified to be 0. It is therefore a valid null pointer constant.
GCC's behavior here is contrary to the language spec.
I don't really see how any of the above has changed in C23 either.
None of the points you were referring to changed in C23, but what did change is the type of false
and true
. In C17, these had type int
. In C23, they have type bool
(a.k.a. _Bool
). As you observe, however, bool
is an integer type, so GCC not allowing that as the type of a null pointer constant is non-conforming.
I note that GCC 8.5 does not accept _Bool
as a valid type for a null pointer constant, either. Given this source:
void *test = (_Bool)0;
int main(void) {
}
, it fails with the same error you observed:
npctest.c:1:14: error: incompatible types when initializing type ‘void *’ using type ‘_Bool’
Thus, your observation appears to be a manifestation of a larger, relatively longstanding issue that is not specific to C23.
This issue is mentioned in the GCC bug tracker in comments on a related issue: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112556.