The compiler would faithfully diagnose an error if the explicit type conversions were removed from
struct rectangle *r = (struct rectangle *) s;
or from
struct triangle *t = (struct triangle *) s;
The explicit type conversions, in this case, are permitted to work because what is what the standard requires. In effect, by using the explicit type conversion in these two statements you are effectively directing the compiler "shut up, I know what I'm doing".
What is more interesting is why the main()
function works at run time, once you have bludgeoned the compiler into submission so it permits the conversion.
The code works because the first member of all three struct
s are the same type. The address of a struct
is equal to the address of its first member, except that the types are different (i.e. a pointer to a struct rectangle
has different type from a pointer to an int
). Therefore (if we ignore the different types), the test s == &(s->type)
will be true. The use of a type conversion deals with that, so (int *)s == &s->type
.
Once your code has completed that test, it is then doing an explicit type conversion on s
. It happens that, in the declaration
struct rectangle *r = (struct rectangle *) s;
that your code has ensured s
is actually the address of a (dynamically allocated) struct rectangle
. Hence the subsequent usage of r
is valid. Similarly in the else if
block, with a struct triangle
.
The thing is, if you made an error, such as
if (s->type == RECTANGLE)
{
struct triangle *t = (struct triangle *) s;
printf("perimeter of triangle: %d
", t->x + t->y + t->z);
}
(i.e. using a struct rectangle
as if it is a struct triangle
) then the compiler will still faithfully permit the type conversion (as discussed above). However, the behaviour is now undefined since s
is not actually the address of a struct triangle
. In particular, accessing t->z
accesses a non-existent member.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…