Nothing in the C Standard mandates that int
and long
must have the same size; further, even if they do have the same size, nothing in the Standard mandates that they have the same representation (among other things, they could have incompatible combinations of padding bits and trap representations, such that aliasing between the two types could not serve any useful purpose).
The authors of the Standard did not want to force implementers targeting platforms where aliasing between int
and long
would serve no purpose to recognize such aliasing. They also did not want to write rules which would be applicable to some platforms (those where aliasing would serve a purpose) but not others (those where it wouldn't). Instead, they figured that people writing quality compilers would try to recognize aliasing in cases where it was useful.
Being able to use pointers to one 32-bit type to read and write values of another 32-bit type that has the same representation is clearly useful, especially if APIs are split as to which type they expect. If some commonplace APIs on a platform use int*
for 32-bit values and others use long*
, a quality general-purpose implementation for that platform must allow data of either type to be accessed using pointers of the other.
Unfortunately, however, the authors of some compilers are more interested in processing a certain subset of programs quickly, than in processing a larger subset of programs usefully, and cannot be relied upon to generate useful code if it's necessary to exchange data between APIs that use the same data representation but different named types unless one completely disables aliasing analysis. Of course, if one is targeting dialects of C that are suitable for general-purpose use on microcontrollers, such issues don't matter.