4
votes
int i = 42;
int *p1 = &i;
int long *p2 = (long*)p1;

Is this undefined behavior? In C++, I think it is implementation defined behavior for some reason.

I looked in C Standard:

C99 6.3.2.3/7 A pointer to an object or incomplete type may be converted to a pointer to a different object or incomplete type. If the resulting pointer is not correctly aligned 57) for the pointed-to type, the behavior is undefined. Otherwise, when converted back again, the result shall compare equal to the original pointer.

57) In general, the concept "correctly aligned" is transitive: if a pointer to type A is correctly aligned for a pointer to type B, which in turn is correctly aligned for a pointer to type C, then a pointer to type A is correctly aligned for a pointer to type C.

What does the term correctly aligned mean here in practice? How do you know if you're doing it correctly without stepping into Undefined behavior?

1
It's Undefined Behavior if you dereference p2. Reason: You violate strict-aliasing. - Mysticial
int long *p2??? what is long here? - Krishnabhadra
On 32bit arch, sizeof(int) == sizeof(long), so there is no difference. On 64 - you'll have some garbage on other half of long, or could even leave allocated memory regions, so again - there is no point to do that. Other than that, it's correct. - keltar
@Krishnabhadra: int long *p2 is a legitimate but slightly unorthodox way of writing signed long int *p2, long *p2, long int *p2 or long int signed *p2 (these are all equivalent to each other). - Jonathan Leffler
In a 64-bit environment on RISC machines, there's a decent chance that i will be aligned on an odd 32-bit address boundary but long must be aligned on a 64-bit address boundary (or even 32-bit address boundary). Therefore, on such systems, you would get a SIGBUS if you tried to read or modify memory via p2. - Jonathan Leffler

1 Answers

4
votes

It basically means that if, say, int is aligned to 4 bytes, and int long is aligned to 8 bytes, the behavior is undefined. Say you have something like:

 0x04     0x08    0x0C    0x10
+------+-------+-------+-------+
|      |       |   i   |       |
+------+-------+-------+-------+

In this case, &i == 0x0C (which is valid because int is aligned to 4 bytes). When you cast to int long*, the pointer is converted to an aligned one: p2 == 0x08, because our theoretical system aligns int long to 8 bytes, so you'd be basically reading off an address you don't own if you dereference p1, ergo the undefined behavior.