To my astonishment, this compiles:
const char* c_str() { static const char nullchar = '\0'; return nullchar; }
and it introduced a bug in my code. Thankfully, I caught it.
Is this intentional by C++, or a compiler bug? Is there a reason why the data type is actively ignored?
It worked in Visual C++ 2010 and GCC, but I don't understand why it should work, given the obvious data type mismatch. (The static
isn't necessary, either.)
char* const says that the pointer can point to a char and value of char pointed by this pointer can be changed. But we cannot change the value of pointer as it is now constant and it cannot point to another char.
const char * const Constant pointer (pointer can't be changed) to constant data (data cannot be modified).
The difference is that const char * is a pointer to a const char , while char * const is a constant pointer to a char . The first, the value being pointed to can't be changed but the pointer can be. The second, the value being pointed at can change but the pointer can't (similar to a reference).
You absolutely can assign const char* to std::string , it will get copied though. The other way around requires a call to std::string::c_str() .
As you've defined it, nullchar
is an integer constant expression with the value 0.
The C++03 standard defines an null pointer constant as: "A null pointer constant is an integral constant expression (5.19) rvalue of integer type that evaluates to zero." To make a long story short, your nullchar
is a null pointer constant, meaning it can be implicitly converted and assigned to essentially any pointer.
Note that all those elements are required for that implicit conversion to work though. For example, if you had used '\1'
instead of '\0'
, or if you had not specified the const
qualifier for nullchar
, you wouldn't get the implicit conversion -- your assignment would have failed.
Inclusion of this conversion is intentional but widely known as undesirable. 0 as a null pointer constant was inherited from C. I'm fairly sure Bjarne and most of the rest of the C++ standard committee (and most of the C++ community in general) would dearly love to remove this particular implicit conversion, but doing so would destroy compatibility with a lot of C code (probably close to all of it).
This is an old history: it goes back to C.
There is no null
keyword in C. A null pointer constant in C is either:
0
, 0L
, '\0'
(remember that char
is an integral type), (2-4/2)
void*
, like (void*)0
, (void*)0L
, (void*)'\0'
, (void*)(2-4/2)
The NULL
macro (not a keyword!) expands to such null pointer constant.
In the first C++ design, only the integral constant expression was allowed as a null pointer constant. Recently std::nullptr_t
was added to C++.
In C++, but not in C, a const
variable of integral type initialized with an integral constant expression is an integral constant expression:
const int c = 3; int i; switch(i) { case c: // valid C++ // but invalid C! }
So a const char
initialized with the expression '\0'
is a null pointer constant:
int zero() { return 0; } void foo() { const char k0 = '\0', k1 = 1, c = zero(); int *pi; pi = k0; // OK (constant expression, value 0) pi = k1; // error (value 1) pi = c; // error (not a constant expression) }
And you think this is not sound language design?
Updated to include relevant parts of C99 standard... According to §6.6.6...
An integer constant expression shall have integer type and shall only have operands that are integer constants, enumeration constants, character constants,
sizeof
expressions whose results are integer constants, and floating constants that are the immediate operands of casts. Cast operators in an integer constant expression shall only convert arithmetic types to integer types, except as part of an operand to thesizeof
operator.
Some clarifications for C++-only programmers:
sizeof
is always a compile time constant; but C has variable length arrays, so sizeof
is sometimes not a compile time constant.Then, we see §6.3.2.3.3 states...
An integer constant expression with the value 0, or such an expression cast to type
void *
, is called a null pointer constant. If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.
To see just how old this functionality is, see the identical mirrored parts in the C99 standard...
§6.6.6
An integer constant expression shall have integer type and shall only have operands that are integer constants, enumeration constants, character constants,
sizeof
expressions whose results are integer constants, and floating constants that are the immediate operands of casts. Cast operators in an integer constant expression shall only convert arithmetic types to integer types, except as part of an operand to thesizeof
operator.
§6.3.2.3.3
An integer constant expression with the value 0, or such an expression cast to type
void *
, is called a null pointer constant. If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With