Specifically, I think the original code will always do what you expect as long as sizeof(long) == sizeof(float), and the alignment is the same. In reality no compiler is gonna do weird stuff unless your hardware target is weird.
If you use a union, your code won't read or write out of bounds, since it will save space for the larger type. Ideally you would also specify _Float32_t and int32_t for some pseudoportability (at least before endianness gets involved), although I'm aware this was not available in 1999.