I want to understand more about int
overflow in C++ on a 64-bit system. So I would like to stick to int
for my understanding without casting / extending the type to unsigned or 64-bit and I am on Intel x64 Ubuntu using VSCode with cmake.
$ g++ --version
g++ (Ubuntu 14.2.0-4ubuntu2) 14.2.0
Copyright (C) 2024 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
The following just shows assertion
failed without the -Woverflow
exception:
int i = 0x80000000;
cout << "i: " << i << ", -i: " << -i << endl; // Output: i: -2147483648, -i: -2147483648
assert(0x80000000 == -0x80000000); // OK
assert(i == -i); // XXX: assert exception. Why!?!
/*
* 0x8000_0000 + 1 = -0x7FFF_FFFF = 0x8000_0001 (Two's compliment)
* 0x8000_0000 - 1 = -0x8000_0001 = 0x7FFF_FFFF
*/
int i = 0x80000000;
int j = i + 1;
cout << i << " (0x" << hex << i << ") + 1 = " << dec << j << " 0x" << hex << j << endl;
assert(j == 0x80000001); // OK
j = i - 1;
cout << dec << i << " (0x" << hex << i << ") - 1 = " << dec << j << " 0x" << hex << j << endl;
assert(j == 0x7FFFFFFF); // XXX: assert exception. Why!?!
The following throws -Woverflow
exception:
int i = 0x80000000; // numeric_limits<int>::min()
int j = 0x7FFFFFFF; // numeric_limits<int>::max()
cout << i << " - " << j << " = " << i - j << endl; // Output: "-2147483648 - 2147483647 = 1"
assert(1 == i - 0x7FFFFFFF); // XXX: integer overflow in expression of type ‘int’ results in ‘1’ [-Woverflow]
assert(1 == (i - j)); // XXX: integer overflow in expression of type ‘int’ results in ‘1’ [-Woverflow]
i = -INT_MIN; // == 0x80000000
assert(j == (i - 0x7FFFFFFF)); // XXX: integer overflow in expression of type ‘int’ results in ‘1’ [-Woverflow]
These assertions pass:
assert(1 == (int)0x80000000 - (int)0x7fffffff);
assert(1 == 0x80000000 - 0x7fffffff);
Here are my questions:
(1) Why would 0x80000000 - 0x7FFFFFFF
overflow? Shouldn't it rightly yield 1
?
(2) Why is the cout
behaviour different from assert
?
(3) Why do some throws assert
exception and some -Woverflow
exception?
I want to understand more about int
overflow in C++ on a 64-bit system. So I would like to stick to int
for my understanding without casting / extending the type to unsigned or 64-bit and I am on Intel x64 Ubuntu using VSCode with cmake.
$ g++ --version
g++ (Ubuntu 14.2.0-4ubuntu2) 14.2.0
Copyright (C) 2024 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
The following just shows assertion
failed without the -Woverflow
exception:
int i = 0x80000000;
cout << "i: " << i << ", -i: " << -i << endl; // Output: i: -2147483648, -i: -2147483648
assert(0x80000000 == -0x80000000); // OK
assert(i == -i); // XXX: assert exception. Why!?!
/*
* 0x8000_0000 + 1 = -0x7FFF_FFFF = 0x8000_0001 (Two's compliment)
* 0x8000_0000 - 1 = -0x8000_0001 = 0x7FFF_FFFF
*/
int i = 0x80000000;
int j = i + 1;
cout << i << " (0x" << hex << i << ") + 1 = " << dec << j << " 0x" << hex << j << endl;
assert(j == 0x80000001); // OK
j = i - 1;
cout << dec << i << " (0x" << hex << i << ") - 1 = " << dec << j << " 0x" << hex << j << endl;
assert(j == 0x7FFFFFFF); // XXX: assert exception. Why!?!
The following throws -Woverflow
exception:
int i = 0x80000000; // numeric_limits<int>::min()
int j = 0x7FFFFFFF; // numeric_limits<int>::max()
cout << i << " - " << j << " = " << i - j << endl; // Output: "-2147483648 - 2147483647 = 1"
assert(1 == i - 0x7FFFFFFF); // XXX: integer overflow in expression of type ‘int’ results in ‘1’ [-Woverflow]
assert(1 == (i - j)); // XXX: integer overflow in expression of type ‘int’ results in ‘1’ [-Woverflow]
i = -INT_MIN; // == 0x80000000
assert(j == (i - 0x7FFFFFFF)); // XXX: integer overflow in expression of type ‘int’ results in ‘1’ [-Woverflow]
These assertions pass:
assert(1 == (int)0x80000000 - (int)0x7fffffff);
assert(1 == 0x80000000 - 0x7fffffff);
Here are my questions:
(1) Why would 0x80000000 - 0x7FFFFFFF
overflow? Shouldn't it rightly yield 1
?
(2) Why is the cout
behaviour different from assert
?
(3) Why do some throws assert
exception and some -Woverflow
exception?
2 Answers
Reset to default 2The moment you have signed integer overflow you have UB in your code and anything can happen (the whole program becomes invalid and you can no longer trust ANY result). Or in other words UB is undetectable by code so you cannot check for it from code.
Side note : When checking for signed integer overflow (UB) make sure you use the std::int64_t or std::int32_t so you know what you get (for int
you don't know).
int
follows two's complement arithmetic. In this arithmetic, the sign is the most significant bit and negative values have bits reversed. So
0x00000000 = 0
0xFFFFFFFF = -1
0x7FFFFFFF = 2^15-1 (maximum value)
0x80000000 = -2^15 (minimum value)
The particularity of two's complement is when you add 1
, you will get the right sign except at the maximum value, where adding one makes all bits change value, including the sign bit. When this happens, we say it is an overflow and is undefined behaviour in C++.
The same is true when substracting 1
, but this time when you substract 1 to the minimum value, all the bits flip to the maximum value. This is also an overflow. Any values above 1
result in an overflow in both cases.
int i=0x80000000; int j=0x7fffffff; i-j
is not the same as0x80000000-0x7fffffff
. The former results in a signed overflow due to the declared types ofi
andj
, the latter is perfectly valid operation between two unsigned integers. Your first question is asking the wrong question. – Weijun Zhou Commented yesterday-Woverflow
may be designed to work only with expressions containing variables, but that's very compiler-specific. – Weijun Zhou Commented yesterdayint
) of(int)0x80000000 - (int)0x7fffffff)
gives undefined behaviour, soassert(1 == (int)0x80000000 - (int)0x7fffffff)
is allowed to pass, it is allowed to fail, or [fortunately, rare in practice] your compiler is permitted to reformat your hard drive. – Peter Commented yesterday