I believe that during arithmetic overflow (in the context of an integer variable being assigned a value too large for it to hold), bits beyond the end of the variable could be overwritten.
But in the following C++11 program does this really still hold? I don’t know whether it’s UB, or disallowed, or implementation-specific or what, but when I take the variable past its maximum value, on a modern architecture, will I actually see arithmetic overflow of bits in memory? Or is that really more of a historical thing?
int main() {
// (not unsigned; unsigned is defined to wrap-around)
int x = std::numeric_limits<int>::max();
x++;
}
It is undefined, as specified in C++11 5/4:
(As you say, it is defined for unsigned types, since they are defined by 3.9.1/4 to obey modular arithmetic)
On all the modern architectures I know of (x86, ARM, 68000, and various DSPs), arithmetic is modular, with fixed-width 2s-complement results; on those architectures that can write the result to memory rather than registers, it will never overwrite more memory than the result size. For addition and subtraction, there is no difference to the CPU between signed and unsigned arithmetic. Overflow (signed or unsigned) can be detected from the state of CPU flags after the operation.
I could imagine a compiler for, say, a 32-bit DSP that tried to implement arithmetic on 8 or 16-bit values packed into a larger word, where overflow would affect the rest of the word; however, all compilers I’ve seen for such architectures just defined
char,shortandintto be 32-bit types.It would have happened on Babbage’s Difference Engine, since “memory” is a single number; if you partition it into smaller numbers, and don’t insert guard digits, then overflow from one will alter the value of the next. However, you couldn’t run any non-trivial C++ program on this architecture.
Historically, I believe some processors would produce an exception on overflow – that would be why the behaviour is undefined.