5 ms·
Yes, most casts via pointers are formally UB in both C and C++, and you can induce weird behavior by compilers if you transmit casted pointers through a functio
by LegionMammal978 2y ago
Yes, most casts via pointers are formally UB in both C and C++, and you can induce weird behavior by compilers if you transmit casted pointers through a function boundary (see [0] for a standard example: notice how the write to *pf vanishes into thin air). Since people like doing it in practice, GCC and Clang have an -fno-strict-aliasing flag to disable this optimization, and the MSVC compiler doesn't use it in the first place (except for restrict pointers in C). They don't go too far with it regardless, since lots of code using the POSIX socket API casts around struct pointers as a matter of course.
Apart from memcpy(), the 'allowed' methods include unions in C (writing to one member and reading from another), and bit_cast<T>() and std::start_lifetime_as<T>() in C++.
[0] https://godbolt.org/z/dxMMfazoq https://godbolt.org/z/dxMMfazoq
- ckjellqv 2y agoIt should be well-defined with reinterpret_cast<uint32_t&> though.
- LegionMammal978 2y agoNo, reinterpret_cast doesn't change the type of the underlying object. The rule in [basic.lval]/11 (against accessing casted values) applies to all glvalues, whether they come from pointers or references.
- rjeli 2y agoFor C++, `bit_cast<uint32_t>(0.f)` should be Well Defined, right? I'm curious, in C, is union-casting float->uint32_t also Perfectly Legal And Well Defined? (I am not a C or C++ expert.)
- ryao 2y agoThere are two additional ways of making this work. The first is to allocate the memory using char a[sizeof(float)]. In C, char pointers may alias anything, so then you can do pointer conversions that would normally be undefined behavior and it should work. The other option is to use the non-standard __attribute__((__may_alias__)) on the pointer. By the way, using union types for this is technically undefined behavior in the C and C++ standards, but GCC and Clang decided to make it defined as an implementation choice. Other compilers might not.
- gpderetta 2y agoThe union trick is actually defined in C. And note that while char can alias anything, the reverse is not true: i.e. you can't generally cast a char array to anything else and expect sensible behaviour. There are ways to make this work (placement new in C++ for example), but it is not a way to escape TBAA: if you store a float in char array you can't then cast it to int with impunity.
- atiedebee 2y agoTo be more precise, it is defined since c99[0]. In c89 it was undefined, but type punning is the most used/sensible behaviour, so they changed it in c99. [0]: https://en.cppreference.com/w/c/language/union https://en.cppreference.com/w/c/language/union
- gpderetta 2y agoYes, it 2025, I thought that we could at least imply C99 when talking about plain C :). I'm probably an optimist.
- ryao 2y agoIt does not matter. The C99 standard does not define this behavior: https://news.ycombinator.com/item?id=42568271m https://news.ycombinator.com/item?id=42568271m
- ryao 2y agoThat is a common misconception. DR 283 is a suggestion for an amendment that was filed 3 years after C99 was published: https://open-std.org/jtc1/sc22/wg14/www/docs/dr_283.htm https://open-std.org/jtc1/sc22/wg14/www/docs/dr_283.htm It is not part of C99. It also is not part of the C standard since no subsequent C standard adopted it according to the GCC developers: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118141#c13 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118141#c13 A read of the C11 standard draft, which would have this amendment if it were accepted by the C standards committee, shows that this has not been added: https://open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf https://open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf Type punning via union types is therefore undefined behavior unless your compiler implements an extension to define it like GCC and Clang do.