3 ms·
No, this is not always undefined behavior. uint8_t start = -1; // Your code uint8_t start = 0xFF; // Absolutely equivalent As for the expression `st
by nayuki 5y ago
No, this is not always undefined behavior.
uint8_t start = -1; // Your code
uint8_t start = 0xFF; // Absolutely equivalent
As for the expression `start << 24`, `start` will always be promoted to `signed int` because `int` is guaranteed to be at least 16 bits wide, so it can hold all `uint8_t` values.
If the width of `int` is 32 bits or narrower, then `start << 24` (which is 0xFF000000) will put a binary 1 into the sign bit, which is indeed undefined behavior.
Otherwise if `int` is 33 bits or wider, then `start << 24` will fit in `int` nicely and be fully defined behavior.
Reasoning about these complicated cases involving implicit conversion (-1 -> 0xFF), promotion (uint8_t -> signed int), and implementation-defined bit widths (how wide is int?) is exactly why I dislike dealing with C and C++.
- astrange 5y agoWhere have you found an ILP64 system? There aren't any - that's why I said "current C". The idea that C programs can survive having the size of their most common type changing is not realistic, though luckily people rarely try.
- nayuki 5y agoYour insistence on "current C" is a brittle claim to make. I'll give you the benefit of the doubt that there are no popular instances of ILP64 systems today. But someday your comment will be false, and it could happen at a surprising time. This would be a repeat of how old C programmers' false assumptions were violated by the 16->32 bit transition, the 32->64 bit transition, and the increasing exploitation of UB for optimization. Whereas my comment is always true with respect to the C11 standard - there can be a legal implementations where `(uint8_t)-1 << 24` is undefined behavior, and other implementations where it is well-defined behavior equal to 0xFF000000. As for writing code that behaves correctly on any legal C implementation, it is certainly possible and I practiced this for years. Go ahead and audit my published programs. It is not easy though, and I have made many mistakes along the way before I figured out how to do it consistently. Although there are many rules that I need to follow, the two most important ones are: Obey the fact that built-in integer types have minimum widths (e.g. char is at least 8, int at least 16, long at least 32); Use size_t for array lengths and indexes.