Is the following well-defined:
char* charPtr = new char[42];
int* intPtr = (int*)charPtr;
charPtr++;
intPtr = (int*) charPtr;
The in
In general, the result is unspecified (5.2.10p7) if the alignment requirements of int
are greater than those of char
, which they usually will be. The result will be a valid value of the type int *
so it can be e.g. printed as a pointer with operator<<
or converted to intptr_t
.
Because the result has an unspecified value, unless specified by the implementation it is undefined behaviour to indirect it and perform lvalue-to-rvalue conversion on the resulting int
lvalue (except in unevaluated contexts). Converting back to char *
will not necessarily round-trip.
However, if the original char *
was itself the result of a cast from int *
, then the cast to int *
counts as the second half of a round trip; in that case, the cast is defined.
In particular, in the case above where the char *
was the result of a new[]
expression, we are guaranteed (5.3.4p10) that the char *
pointer is appropriately aligned for int
, as long as sizeof(int) <= 42
. Because the new[]
expression obtains its storage from an allocation function, 3.7.4.1p2 applies; the void *
pointer can be converted
to a pointer of any complete object type with a fundamental alignment requirement and then used to access the object [...] which strongly implies, along with the note to 5.3.4p10, that the same holds for the char *
pointer returned by the new[]
expression. In this case the int *
is a pointer to an uninitialised int
object, so performing lvalue-to-rvalue conversion on its indirection is undefined (3.8p6), but assigning to its indirection is fully defined. The int
object is in the storage allocated (3.7.4.1p2) so converting the int *
back to char *
will yield the original value per 1.8p6. This does not hold for the incremented char *
pointer as unless sizeof(int) == 1
it is not the address of an int
object.
First, of course: the pointer is guaranteed to be aligned in the
first case (by §5.3.4/10 and §3.7.4.1/2), and may be correctly
aligned in both cases. (Obviously, if sizeof(int) == 1
, but
even when this is not the case, an implementation doesn't
necessarily have alignment requirements.)
And to make things clear: your casts are all reinterpret_cast
.
Beyond that, this is an interesting question, because as far as
I can tell, there is no difference in the two casts, as far as
the standard is concerned. The results of the conversion are
unspecified (according to §5.2.10/7); you're not even guaranteed
that converting it back into a char*
will result in the
original value. (It obviously won't, for example, on machines
where int*
is smaller than a char*
.)
In practice, of course: the standard requires that the return
value of new char[N]
be sufficiently aligned for any value
which may fit into it, so you are guaranteed to be able to do:
intPtr = new (charPtr) int;
Which has exactly the same effect as your cast, given that the
default constructor for int
is a no-op. (And assuming that
sizeof(int) <= 42
.) So it's hard to imagine an implementation
in which the first part fails. You should be able to use the
intPtr
just like any other legally obtained intPtr
. And the
idea that converting it back to a char*
would somehow result
in a different value from the original char*
seems
preposterous.
In the second part, all bets are off: you definitely can't
dereference the pointer (unless your implementation guarantees
otherwise), and it's also quite possible that converting it back
to char*
results in something different. (Imagine a word
addressed machine, for example, where converting a char*
to an
int*
rounds up. Then converting back would result in
a char*
which was sizeof(int)
higher than the original. Or
where an attempt to convert a misaligned pointer always resulted
in a null pointer.)