(Sorry, I've only just noticed this question is tagged as c
, not c++
. Maybe my answer isn't so relevant to this question after all!)
String literals are not quite const
or not-const
, there is a special strange rule for literals.
(Summary: Literals can be taken by reference-to-array as foo( const char (&)[N])
and cannot be taken as the non-const array. They prefer to decay to const char *
. So far, that makes it seem like they are const
. But there is a special legacy rule which allows literals to decay to char *
. See experiments below.)
(Following experiments done on clang3.3 with -std=gnu++0x
. Perhaps this is a C++11 issue? Or specific to clang? Either way, there is something strange going on.)
At first, literals appears to be const
:
void foo( const char * ) { std::cout << "const char *" << std::endl; }
void foo( char * ) { std::cout << " char *" << std::endl; }
int main() {
const char arr_cc[3] = "hi";
char arr_c[3] = "hi";
foo(arr_cc); // const char *
foo(arr_c); // char *
foo("hi"); // const char *
}
The two arrays behave as expected, demonstrating that foo
is able to tell us whether the pointer is const
or not. Then "hi"
selects the const
version of foo
. So it seems like that settles it: literals are const
... aren't they?
But, if you remove void foo( const char * )
then it gets strange. First, the call to foo(arr_c)
fails with an error at compile time. That is expected. But the literal call (foo("hi")
) works via the non-const call.
So, literals are "more const" than arr_c
(because they prefer to decay to the const char *
, unlike arr_c
. But literals are "less const" than arr_cc
because they are willing to decay to char *
if needed.
(Clang gives a warning when it decays to char *
).
But what about the decaying? Let's avoid it for simplicity.
Let's take the arrays by reference into foo instead. This gives us more 'intuitive' results:
void foo( const char (&)[3] ) { std::cout << "const char (&)[3]" << std::endl; }
void foo( char (&)[3] ) { std::cout << " char (&)[3]" << std::endl; }
As before, the literal and the const array (arr_cc
) use the const version, and the non-const version is used by arr_c
. And if we delete foo( const char (&)[3] )
, then we get errors with both foo(arr_cc);
and foo("hi");
. In short, if we avoid the pointer-decay and use reference-to-array instead, literals behave as if they are const
.
Templates?
In templates, the system will deduce const char *
instead of char *
and you're "stuck" with that.
template<typename T>
void bar(T *t) { // will deduce const char when a literal is supplied
foo(t);
}
So basically, a literal behaves as const
at all times, except in the particular case where you directly initialize a char *
with a literal.