Most C++ implementations employ two's complement representation of signed
integers, with no trapping.
That means arithmetic modulo 2^n, just as with unsigned integers.
Many, including me, have argued that the C++ standard should stop
supporting the ENIAC, MANIAC and NUSSE computers, and require two's
complement no-trapping representation.
This is not the only issue.
I remember, from many years ago, a major argument that arose within AT&T
between two organizations, one of which was supplying a compiler and the
other of which was using it. The dispute arose around a statement of the
form
if ((x = y - z) < 0) { ... }
The compiler generated machine code that did the following:
Copy y into a register
Subtract z from the register
Copy the register into memory
If the condition code did not indicate that the last arithmetic
computation
yielded a negative result, jump over the code in braces.
Looks straightforward enough, right? But if y-z overflowed, the condition
code indicated that the result of the last operation was an overflow, which
is different from a negative result. Therefore the code in braces was not
executed, even if the result after the overflow happened to be negative.
In other words, if an overflow occurred, it was possible that x might be
negative, but the code in braces was still not executed.
The programmers tried to rewrite the code this way:
x = y - z;
if (x < 0) { ... }
and found that the compiler generated exactly the same code: The optimizer
realized that the if statement could be reached only from the assignment, so
it assumed that the hardware was correctly reflecting the results of the
last computation.
The developers claimed that this state of affairs reflected a compiler bug.
If you test whether a variable is negative, and the test fails, it is a bug
if the variable is subsequently found to be negative.
The compiler people claimed that the underflow resulted in undefined
behavior, so all bets were off. Moreover, if they were to fix this "bug",
it would result in generating a needless extra instruction in a wide variety
of contexts, merely to defend against programming techniques that no one
should be using anyway.
Ultimately, the compiler people won; and their philosophy has persisted to
this day.