Okay. By why do all compilers accept this code? foo("123") should produce
a type mismatch error.
At least Scott Meyers has the same opinion:
[...] is technically illegal (it's a violation of const correctness). In
practice, I expect
all compilers to accept such code [...]
I tested Comeau, Digital, Visual and Watcom. All of them accepted the code.
Most binaries worked - only VC crashed as the compiler put the literal in a
const segment.
I for my part plead for C++ leaving its ancestry behind and become a real
typesafe
language!
void foo (char* p) { // accepts "123" and fails!
*p = 'X';
}
int main () {
char s[] = "ABC";
foo (s);
foo ("123"); // Visual C++ will crash!
// Digital, Watcom C++ won't crash!
return 0;
}
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
> I was fiddling around with a problem when I ran into an issue that struke
> me.
> The following code causes an access violation. Correct. "123" is an array of
> const char (that's what the standard says).
But it also says that you can assign a string literal to a char *,
simply because C allowed it.
> Okay. By why do all compilers accept this code? foo("123") should produce
> a type mismatch error.
No, see above.
> At least Scott Meyers has the same opinion:
>
> [...] is technically illegal (it's a violation of const correctness). In
> practice, I expect
> all compilers to accept such code [...]
It is technically illegal, but an exception that is allowed for
backwards compatibility.
> I tested Comeau, Digital, Visual and Watcom. All of them accepted the code.
> Most binaries worked - only VC crashed as the compiler put the literal in a
> const segment.
Which is also a valid thing to do, because you're writing into a
constant string and thus triggering undefined behavior. Everything can
happen, including nothing, or a crash. Note that "..." *has still* the
type const char[], and not char[]. It can only be assigned to a char *,
with all possible side-effects you should be worried about.
> I for my part plead for C++ leaving its ancestry behind and become a real
> typesafe
> language!
Why do you then use char * and not std::string? (-:
So long,
Thomas
It's UB -- accessing a const via a non-const pointer.
> Okay. By why do all compilers accept this code? foo("123") should produce
> a type mismatch error.
4.2/2 "A string literal (2.13.4) that is not a wide string literal can
be converted to an rvalue of type "pointer to char"; ... [Note: this
conversion is deprecated. See Annex D. ]"
Try GCC with -Wwrite-strings
(the code in question being void foo (char* p) )
This is because there is one exception to this const correctnes - the
implicit conversion from constant literal character array to char* is
allowed - apparently because lots of legacy code that would otherwise
stop to compile.
[snip]
>
> I for my part plead for C++ leaving its ancestry behind and become a real
> typesafe
> language!
>
That statement is a bit heash! I would love compilers to give a warning
for that conversion, but they can not (in any mode) diagnose it as an
error.
[snip]
/Peter
Because 4.2/2 explicitly makes it legal (but deprecated).
Because the standard explicitly requires this conversion in §4.2/2
(although it's deprecated). So the behavior you are experiencing is
actually compliant to the standard.
> I for my part plead for C++ leaving its ancestry behind and become a real
> typesafe language!
Completely agree.
Ganesh
PS: all compilers you have tested (except maybe for Comeau) are known to
be non-compliant, but not for this reason ;-)
> I was fiddling around with a problem when I ran into an issue that struke
> me.
> The following code causes an access violation. Correct. "123" is an array of
> const char (that's what the standard says).
>
> Okay. By why do all compilers accept this code? foo("123") should produce
> a type mismatch error.
>
> At least Scott Meyers has the same opinion:
>
> [...] is technically illegal (it's a violation of const correctness). In
> practice, I expect
> all compilers to accept such code [...]
>
Not so sure, char s[] = "ABC"; is a non const char array large
enough to hold "ABC" and intialized with the data of "ABC", not a
pointer to the const "ABC". That is it is a COPY of "ABC" not "ABC".
> I tested Comeau, Digital, Visual and Watcom. All of them accepted the code.
> Most binaries worked - only VC crashed as the compiler put the literal in a
> const segment.
>
> I for my part plead for C++ leaving its ancestry behind and become a real
> typesafe
> language!
>
> void foo (char* p) { // accepts "123" and fails!
> *p = 'X';
> }
>
> int main () {
> char s[] = "ABC";
> foo (s);
> foo ("123"); // Visual C++ will crash!
> // Digital, Watcom C++ won't crash!
> return 0;
> }
Off hand I would say that your VC++ is non compliant. It is treating
it as if main() began with
int main()
{
char *s = "ABC";
// ...
}
which not the same as your main(). Your main says s is a char[4]
intialized to {'A','B','C','\0'} not a pointer to "ABC"; and as such
foo should work with no faults or exceptions.
Maybe you should plead for compliance of your compiler and not
modification of the standard to match a non compliant compiler.
BTW my CW 9 works with your code s becomes "XBC", as expected.
No, although normal string literal's type is "array of N const char",
but according to 4.2 "array-to-pointer conversion", we have a standard
conversion ( deprecated one ) from string literal to "pointer to char".
BTW, In the old days, string literal's type was "array of N char".
The const was added to improve the typing system of C++.
See below.
> At least Scott Meyers has the same opinion:
>
> [...] is technically illegal (it's a violation of const correctness). In
> practice, I expect
> all compilers to accept such code [...]
>
As explained, the code is valid, but deprecated.
The rationale can be found at Annex C&D,
[quote]
Subclause _lex.string:
Change:String literals made const
The type of a string literal is changed from "array of char" to
"array
of const char." The type of a wide string literal is changed from
"array of wchar_t" to "array of const wchar_t."
Rationale: This avoids calling an inappropriate overloaded function,
which might expect to be able to modify its argument.
Effect on original feature:Change to semantics of well-defined feature.
Difficulty of converting: Simple syntactic transformation, because
string
literals can be converted to char*; (4.2). The most common cases are
handled by a new but deprecated standard conversion:
char* p = "abc"; // valid in C, deprecated in C + +
char* q = expr ? "abc" : "de"; // valid in C, invalid in C + +
How widely used: Programs that have a legitimate reason to treat string
literals as pointers to potentially modifiable memory are probably
rare.
> I tested Comeau, Digital, Visual and Watcom. All of them accepted the code.
> Most binaries worked - only VC crashed as the compiler put the literal in a
> const segment.
>
They are correct according to the standard.
However, some of them will issue warning/remark for you.
For example, gcc will warn you if you specify the -Wwrite-strings
flag.
$ gcc -Wwrite-strings sl.cpp
sl.cpp: In function `int main()':
sl.cpp:9: warning: deprecated conversion from string constant to
`char*'
> I for my part plead for C++ leaving its ancestry behind and become a real
> typesafe
> language!
>
Well, I do not see any difficulties to prohibit the *new* deprecated
conversion. However, this will break lots of legacy code and I do
not see the benefit. For this issue I see the design trade-off and
I believe this kind of trade-offs made C++ a both usable/productive
and type-safe (strong, or weak. I donot really care about it) language.
BTW, I suggest you read D&E, which shows me lots of points
for how to make a choice. Yes, making a choice is always difficult.