But please change the standard to disallow 00UB:
https://gavinhoward.com/2023/08/the-scourge-of-00ub/
I have to do a lot of stuff to avoid UB in my code. I even implemented UB-free two's complement arithmetic using unsigned types just to avoid all of the problems.
And it has definitely gone too far when people think that the compiler doing anything on UB is the definition of UB, not just a side effect.
"Note 3 to entry: Any other behavior during execution of a program is only affected as a direct consequence of the concrete behavior that occurs when encountering the erroneous or non-portable program construct or data. In particular, all observable behavior (5.1.2.4) appears as specified in this document when it happens before an operation with undefined behavior in the execution of the program."
^1 https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3220.pdf
However, I think that consistency should win here. Given that unsigned arithmetic already wraps around - and this cannot be changed for backwards compatibility reasons - making signed arithmetic do something different is just bad design. It would certainly be better if the default behavior was to trap rather than wraparound or saturate, but, well, we're talking here about a language that is >50 years old, so that ship has sailed.
It would sure be nice to get proper dedicated operators for trapping and saturating arithmetic in some future version of the C standard, though.
You are correct, but I care about correctness more. I will use a lobrary to get it.
That said, having such checks by default would surely reduce the possible impact of overflow on security, so I would support it.
C is low-level enough that it's not particularly useful to think in those terms, IMO. If you're writing in C, it's usually for one of the two reasons: either you want to be "close to the metal" because you're doing low-level stuff, or it's a legacy codebase. From the first perspective, I can't think of any "modern" - as in, past three decades - architecture for which signed wraparound is not the default & fastest behavior. From the second perpective, a lot of legacy code actually assumes signed wraparound (because compilers used to just defer to what the hardware actually did).
FWIW the reason why C had UB for signed overflow historically is because back when it was being standardized, there were still machines around that used something other than two's complement to represent signed values. The original ANSI C89 straight up refused to specify the signed representation, and C99 narrowed it down to several options; thus, the obvious hardware implementation would in fact produce different results on overflow. Conversely, unsigned integers always had a well-defined representation for which wraparound was simply the natural hardware behavior. I don't think this was ever meant to have some kind of higher meaning.
Given that C23 explicitly mandates two's complement for signed now, IMO, the signed overflow behavior should just be made consistent with that as well as real-world hardware. The only claimed downside to this is that compilers can no longer "optimize" code that was previously broken but would now be well-defined, but I don't see why that is an actual problem.
I am programming C because Python is too slow for my use case (and too annoying and to unstable) and yes, I use C's integer types as an abstraction for mathematical integers. And I would say this is the case in almost all C code I see and most programmers I talk to. How would two-complement's wrapping for int be useful for anything? It does not model anything useful IMHO.
And the problem with compilers not optimizing is that people want them to optimize... Compilers not being able to to do this as well anymore would indeed be an actual problem for many people.
Making it UB in ISO C ensures that no portable program can rely on a specific behavior and this is what makes it possible to find bugs this way, because it is plausible to assume that a program with overflow is buggy. This is also why this does not work for unsigned. We can easily change a compiler to trap on unsigned wraparound. But this is mostly useless because there would be far too many false positives.
This is true.
> and this is what makes it possible to find bugs this way
No, this is not true. In fact, it is the opposite of true.
If a program cannot rely on behavior, it cannot rely on having the behavior that causes the bug to be visible.
For this reason, signed overflow is essentially a solved problem, while unsigned wraparound will be the source for many interesting bugs - exactly because it is not UB!
Does the compiler faithfully compile the source code with sanitizers? Of course not, so we still cannot rely on them.
> So you can not distinguish between intended wraparound and incorrect wraparound.
This is exactly why I implemented both types in my arithmetic. The one I used is the one I intended.