4 ms·
>C was created for writing operating systems That doesn't properly justify C's minefield around aliasing and type punning in general. It's UB galore. Thing is,
by simias 8y ago
>C was created for writing operating systems
That doesn't properly justify C's minefield around aliasing and type punning in general. It's UB galore. Thing is, whenever you're writing low level code that's tied to hardware in my experience you very often end up having to pun your types to match hardware constraints, and at this point the C standard basically says "lol good luck with that bro".
I'm not a programming language expert but IMO at the very least C should make reading from a different union member than was last written to "implementation defined" instead of UB (with suitable constraints if the sizes of the members differ I suppose). In effect that's mostly how compilers deal with that anyway.
So I agree with Linus that the C standard is really unhelpful in these situation, although his childish anger is unnecessary and counter-productive.
- pubby 8y ago>at the very least C should make reading from a different union member than was last written to "implementation defined" That's how it is :) The standard even describes union behavior as "type punning". I don't know if C++ allows it though.
- maccard 8y agoDon’t think c++ allows it. Last time I checked, if you use any modern compiler, and do a memcpy, and check the assembly, it does the right thing.
- saagarjha 8y agoYes, that's the "approved" way of doing type punning. Any decent compiler will immediately optimize that down to nothing.
- simias 8y agoYou're right, apparently it changed in C99 so my knowledge is pretty out of date. Thank you for pointing it out.
- TorKlingberg 8y agoType punning through a union is allowed, buy you have to be careful so the compiler can see the union. union { int i; float f; } u; You can't safely call a function with pointers to the members like func(&u.i, &u.f), because when func was compiled, the compiler couldn't know that the arguments are pointers to union members. This sort of thing scares me, because what the compiler can "see" isn't well defined. Is it ok if func is in the same file? Probably not. How about if I don't send the pointers to an other function and just use them locally? Probably ok, but I wouldn't trust it. If you want to type pun with a union, make sure to always access the members through the union, not with direct pointers. The only method of type punning I 100% trust is memcpy, and if you get lucky the compiler might optimize away the overhead for you.
- boomlinde 8y agoAssuming we're talking C, not C++, the compiler doesn't need to know that the arguments are pointers to union members, because the union members are all aligned with the union itself and have the same address. So &u.f is not some magic special pointer, it's the address of a float. So is (float *)&u. The example in the standard I think you're referring to relates to a special guarantee made about unions of structs that have a common initial sequence, that their common initial sequence can be read from either union member (AFAIK a guarantee not otherwise made about structs that share a common initial sequence). If your func(&u.i &u.f) example fails it may be because the standard is picky about pointers of different types to the same memory. I have no idea whether it is, because I've never had to do anything like your example.
- BruiseLee 8y agoThe func can be implemented like this: float func(int *i, float *f) { *i = 42; return *f; } Since the compiler assumes that the pointers i and f do not alias, it has a right to generate the code that is equivalent to: float func(int *i, float *f) { float result = *f; *i = 42; return result; } But this will change the result of the function. So in practice if you want to do type punning using unions, the compiler must know about it.
- B1FF_PSUVM 8y ago> childish anger The whole world needs betrization soonest ( https://en.wikipedia.org/wiki/Return_from_the_Stars https://en.wikipedia.org/wiki/Return_from_the_Stars )
- boomlinde 8y agoMaybe I suck at reading the standard, but it seems that type punning via unions is defined in C99: "If the member used to access the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type as described in 6.2.6 (a process sometimes called "type punning")."