The expression *ipp
is an lvalue of type int *
, however it is being used to access an object of effective type const int *
. (Namely, cip
).
According to the letter of the standard, it is a strict aliasing violation: the list of allowed types to alias does not include aliasing T *
as const T *
or vice versa.
The closest exception is this one: (C11 6.5/6 excerpt)
- a qualified version of a type compatible with the effective type of the object
"qualified version" is clearly defined by C11 6.2.5/26:
Each unqualified type has several qualified versions of its type, corresponding to the combinations of one, two, or all three of the const
, volatile
, and restrict
qualifiers. The qualified or unqualified
versions of a type are distinct types that belong to the same type category and have the same representation and alignment requirements. A derived type is not qualified by the qualifiers (if any) of the type from which it is derived.
So the exception is that T
may be aliased as const T
and vice versa, but there is no similar exception for pointers to aliasable types. const T *
is not a qualified version of T *
.
However there is of course the footnote:
The intent of this list is to specify those circumstances in which an object may or may not be aliased
I couldn't say whether the intent of the rule is for const T *
and T *
to be aliasable or not. It seems unclear to me what the purpose of specifying that T *
and const T *
have "the same representation and alignment requirements" (6.2.5/28) would be if it is not aliasable.
int *ip = (int *)cip;
is not OK. Your compiler should complain about shedding theconst
. If not use higher warning levels. Or what kind of "OK" are you thinking of? "works", "works reliably", "works portably", "is good code", ... – Pellegrinoconst
. That's how you tell the compiler not to issue any warnings. The first code snippet is perfectly legal C. – Guennaint *ip = ...;
is very different from*ip = ...;
. Just reading through a pointer should be fine, writing through it is undefined though. – Pittsburgh*ip = (int *)cip
in the above code (that would make no sense at all, since*ip
isint
). As forint *ip = (int *)cip;
... There's no fault of any kind inint *ip = (int *)cip;
regardless of what kind of storageci
is stored in. The "fault" will occur if you do*ip = 56
after that. Butint *ip = (int *)cip;
is not only perfectly valid code, but a valuable implementational idiom widely used in C programming. – Guennaconst
it is "needed" or "not needed" here. The very same shedding ofconst
is used inside, say, standardstrchr
function. And there it is needed for rather obvious purpose. – Guenna(char *)
cast is only okay due to the "character type" exception, which is why I've usedint
everywhere in this example. – Pittsburghconst
object. – Guenna