有符号和无符号整数表达式与0x80000000之间的比较

Ada*_*dam 5 c++

我有以下代码:

#include <iostream>

using namespace std;

int main()
{
    int a = 0x80000000;
    if(a == 0x80000000)
        a = 42;
    cout << "Hello World! :: " << a << endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出是

Hello World! :: 42
Run Code Online (Sandbox Code Playgroud)

所以比较有效.但是编译器告诉我

g++ -c -pipe -g -Wall -W -fPIE  -I../untitled -I. -I../bin/Qt/5.4/gcc_64/mkspecs/linux-g++ -o main.o ../untitled/main.cpp
../untitled/main.cpp: In function 'int main()':
../untitled/main.cpp:8:13: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
     if(a == 0x80000000)
             ^
Run Code Online (Sandbox Code Playgroud)

所以问题是:为什么0x80000000是unsigned int?我可以以某种方式签名以摆脱警告吗?

据我所知,0x80000000将是INT_MIN,因为它超出正整数的范围.但为什么编译器会假设我想要一个正数?

我正在使用linux上的gcc版本4.8.1 20130909进行编译.

650*_*502 6

0x80000000是一个unsigned int,因为该值太大int而不适合a 并且您没有添加任何L指定它是一个long.

发出警告是因为unsigned在C/C++中有一个非常奇怪的语义,因此通过混合有符号和无符号整数很容易在代码中出错.这种混合通常是错误的来源,特别是因为历史事故标准库选择使用无符号值来表示容器的大小(size_t).

我经常用一个例子来说明问题的微妙程度

// Draw connecting lines between the dots
for (int i=0; i<pts.size()-1; i++) {
    draw_line(pts[i], pts[i+1]);
}
Run Code Online (Sandbox Code Playgroud)

这段代码似乎很好,但有一个bug.如果pts向量是空的pts.size(),0但是,这里出现了令人惊讶的部分,pts.size()-1是一个巨大的无意义数字(今天经常是4294967295,但取决于平台)并且循环将使用无效索引(具有未定义的行为).

在这里更改变量size_t i将删除警告但不会有帮助,因为同样的bug仍然存在...

问题的核心是使用无符号值a < b-1,a+1 < b即使对于非常常使用的值(如零)也不一样; 这就是为什么对容器大小这样的非负值使用无符号类型是一个坏主意和bug的来源.

另请注意,在该值不适合整数的平台上,您的代码不是正确的可移植C++,因为溢出的行为是针对unsigned类型定义的,而不是针对常规整数定义的.依赖于整数超过限制时发生的事情的C++代码具有未定义的行为.

即使你知道在特定的硬件平台说明会发生什么,编译器/优化器是不允许假设符号整数溢出从未发生过:比如像一个试验a < a+1,其中a是有规律的int,可以随时审议了一个C++编译器实现.