I believe the problem is the constraints specified in C99 6.5.16.1(1), which seem to prohibit mixing qualifications in assignments, except for pointers for which an inclusive-qualifier exception is defined. The problem is that with indirect pointers, you end up passing a pointer to one thing to a pointer to another. The assignment isn't valid because, if it was, you could fool it into modifying a const-qualified object with the following code:
const char **cpp;
char *p;
const char c = 'A';
cpp = &p; // constraint violation
*cpp = &c; // valid
*p = 0; // valid by itself, but would clobber c
It might seem reasonable that cpp
, which promises not to modify any char
s, might be assigned a pointer to an object pointing at non-qualified char
s. After all, that's allowed for single-indirect pointers, which is why, e.g., you can pass a mutable object to the second parameter of strcpy(3)
, the first parameter to strchr(3)
, and many other parameters that are declared with const
.
But with the indirect pointer, at the next level, assignment from a qualified pointer is allowed, and now a perfectly unqualified pointer assignment will clobber a qualified object.
I don't immediately see how a 2-D array could lead to this situation, but in any case it hits the same constraint in the standard.
Since in your case, you aren't actually tricking it into clobbering a const, the right thing for your code would seem to be inserting the cast.
Update: OK guys, as it happens this issue is in the C faq, and this entire discussion has also taken place several times on the gcc bug list and on the gcc mailing list.
The lesson: you can pass a T *x
when const T *x
is expected, by explicit exception, but T *x
and const T *x
are still distinct types, so you can't pass a pointer to either one to a pointer to the other.
You should declare your constant string as follows:
NSString * const kSomeConstantString = @""; // constant pointer
instead of:
const NSString * kSomeConstantString = @""; // pointer to constant
// equivalent to
NSString const * kSomeConstantString = @"";
The former is a constant pointer to an NSString
object, while the latter is a pointer to a constant NSString
object.
Using a NSString * const
prevents you from reassigning kSomeConstantString to point to a different NSString
object.
The method isEqualToString:
expects an argument of type NSString *
. If you pass a pointer to a constant string (const NSString *
), you are passing something different than it expects.
Besides, NSString
objects are already immutable, so making them const NSString
is meaningless.
Best Answer
It doesn't violate the standard. That's why they're warnings and not errors.
And indeed you're right — the leading
const
is superfluous. The compiler warns you because you've added code that in other circumstances might mean something, but in this circumstance means nothing, and it wants to make sure you won't be disappointed later when your return values turn out to be modifiable after all.