The -Wwrite-strings can cause it to omit the required diagnostic for
the following:
const char (*p)[6] = &"hello";
Without -Wwrite-strings, this would go undiagnosed:
char (*q)[6] = &"hello";
Yes, the language doesn't require a diagnostic (though an
implementation is free to issue one anyway).
Gcc compiles it without any warnings.
The declaration is potentially dangerous; the gcc developers
apparently decided that the way to avoid the danger is to use
-Wwrite-strings.
Note that the example uses a pointer to a fixed-size array, something
that's rather rare outside the context of multidimensional arrays.
Strings and arrays are much more commonly manipulated using a pointer
to the element type, with some other method (a separate count or a
terminator) defining the length.
If the declaration of p violates a constraint, and the declaration
of q doesn't, one would expect that the language designers had a good
reason to make it that way. At first sight, it looks like q has more
opportunity for misuse than p has. So I am still curious to know about
situations where it's the other way around.
The *only* reason for making string literals non-const is backward
compatibility. K&R C (pre-ANSI) didn't have the "const" keyword, so
if you had a function like this:
func(s)
char *s;
{
/* ... */
}
there was no way to specify that the function wouldn't modify the data
pointed to by s. If ANSI had made string literals const, then given the
above definition, this call:
func("hello");
would have become a constraint violation, breaking tons of existing
code. ANSI also added "const", so you could change the function
definition to:
void func(const char *s)
{
/* ... */
}
but forcing so much code to be changed would likely have greatly
reduced acceptance of the standard.
Few people would disagree that making string literals const would have
been better if the language were being designed from scratch today,
but that's no longer possible. (<OT>C++ did make string literals
const; there wasn't as much concern for maintaining backward
compatibility with C.</OT>)
[...]
I have been using -Wwrite-strings for a long time and so far have
found it advantageous. Now (to my surprise) it turns out that
it's not such a nice option after all, if it can silently produce
UB, e.g. by running a program that contains a p-like declaration.
I wouldn't worry about it. In a sense, -Wwrite-strings causes gcc to
compile a language that's subtly different from C -- and one could
argue that it's a *better* language. One drawback as with any
language extension, conforming or not, is that it can make more
difficult to be sure that your code conforms to the standard and will
be portable to other compilers.
So here's a dilemma: should one dump a useful option, just because it
can result in undefined behaviour for certain contrived (sorry) programs?
Perhaps a solution would be to build the code both with, and without
the option enabled, and make sure it compiles cleanly in both situations.
That's not a bad idea.