Joe said:
Given..
int *ip;
We can do 'ip = malloc(sizeof *ip);
And now,
void *vp = ip;
..is valid. Why do you think not?
What you've just demonstrated is implicit conversion. Many types are
implicitly convertible to other types; section 6.3 is devoted to
describing the many ways in which this can happen. For instance, signed
char is implicitly convertible to long double _Complex. that doesn't
make them compatible.
The term "compatible types" is defined by the C standard in section
6.2.7, with cross-references to several other sections. Follow all of
those cross-references, and you won't find anything that makes "int*"
compatible with "void*".
There are only a few situations where you can access an object using an
lvalue of a one type, if the effective type of the actual object is
different. They are listed in 6.5p7, and the first one is if the lvalue
has " a type compatible with the effective type of the object". Because
int* is not compatible with void*, that case doesn't apply to this code.
Neither do any of the other cases listed in 6.5p7. Therefore, the
behavior of the program is undefined.
It might work as expected, that's one of the possibilities allowed when
the behavior of a program is undefined. On many implementations all
pointers have the same size, alignment, and representation, and on such
implementations this code could work. However, real implementations of C
have different representations for pointers to different types, and even
different sizes. This code will break on any such implementation.