最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c++ - integer overflow in expression of type ‘int’ results in ‘1’ [-Woverflow] - Stack Overflow

programmeradmin5浏览0评论

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?

Share Improve this question edited yesterday khteh asked yesterday khtehkhteh 3,94210 gold badges58 silver badges103 bronze badges 7
  • 5 Expressions that produce overflow of signed integral types in C++ gives undefined behaviour according to the standard. So there is no "right" result. – Peter Commented yesterday
  • 2 0x80000000 is a minimal negative 32 bit value. If you substract any positive number then you get integer overflow. – 3CxEZiVlQ Commented yesterday
  • 1 int i=0x80000000; int j=0x7fffffff; i-j is not the same as 0x80000000-0x7fffffff. The former results in a signed overflow due to the declared types of i and j, the latter is perfectly valid operation between two unsigned integers. Your first question is asking the wrong question. – Weijun Zhou Commented yesterday
  • 1 @khteh That is UB. It just happens to pass. -Woverflow may be designed to work only with expressions containing variables, but that's very compiler-specific. – Weijun Zhou Commented yesterday
  • 1 The nature of undefined behaviour (as per the standard) is that the standard does not impose any constraints or requirements on the result. When behaviour is undefined, any result - whether it makes sense to the programmer or not - is allowed. The evaluation (assuming a 32-bit int) of (int)0x80000000 - (int)0x7fffffff) gives undefined behaviour, so assert(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
 |  Show 2 more comments

2 Answers 2

Reset to default 2

The 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.

发布评论

评论列表(0)

  1. 暂无评论