C++ 有符号和无符号整数表达式与0x8000000之间的比较
我有以下代码:C++ 有符号和无符号整数表达式与0x8000000之间的比较,c++,C++,我有以下代码: #include <iostream> using namespace std; int main() { int a = 0x80000000; if(a == 0x80000000) a = 42; cout << "Hello World! :: " << a << endl; return 0; } 因此,这种比较是有效的。但是编译器告诉我 g++ -c -pipe -g
#include <iostream>
using namespace std;
int main()
{
int a = 0x80000000;
if(a == 0x80000000)
a = 42;
cout << "Hello World! :: " << a << endl;
return 0;
}
因此,这种比较是有效的。但是编译器告诉我
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)
^
所以问题是:为什么0x8000000是一个无符号整数?我能让它签名以摆脱警告吗
据我所知,0x8000000将是INT_MIN,因为它超出了正整数的范围。但是为什么编译器会假设我想要一个正数呢
我正在使用linux上的gcc版本4.8.1 20130909进行编译。
0x8000000
是一个未签名的int,因为该值太大,无法放入int
中,并且您没有添加任何L
来指定它是一个长整数
发出此警告是因为C/C++中的无符号
具有非常奇怪的语义,因此很容易通过混合有符号整数和无符号整数在代码中出错。这种混合通常是bug的来源,特别是因为标准库在历史上偶然选择了使用未签名的值作为容器的大小(size\t
)
我经常用一个例子来说明这个问题是多么微妙
// Draw connecting lines between the dots
for (int i=0; i<pts.size()-1; i++) {
draw_line(pts[i], pts[i+1]);
}
//在点之间画连接线
对于(int i=0;i0x8000000)而言,默认情况下视为无符号。
您可以避免这样的警告:
if (a == (int)0x80000000)
a=42;
评论后编辑:
另一种(也许更好)方法是
if ((unsigned)a == 0x80000000)
a=42;
似乎您混淆了两个不同的问题:某物的编码和某物的含义。下面是一个示例:您看到一个数字97。这是一个十进制编码。但是这个数字的含义完全不同。它可以表示ASCII“a”字符、非常热的温度、几何图形三角形中的所有角度等。您无法从编码中推断含义。必须有人向您提供上下文(如ASCII地图、温度等)
回到您的问题:0x8000000
是编码。而INT\u MIN
是含义。它们不可互换,也不可比较。在某些上下文中,在特定硬件上,它们可能与97相同,而在ASCII上下文中,“a”是相等的
编译器会警告您意义上的歧义,而不是编码上的歧义。赋予特定编码意义的一种方法是强制转换运算符。例如(无符号短)-17
或(student*)ptr;
在32位系统或64位具有反向兼容性int
和unsigned int
的系统上,编码为32位,如0x8000000
,但在64位上MIN_int
不等于此数字
无论如何-你的问题的答案是:为了删除警告,你必须为比较的左表达式和右表达式提供相同的上下文。
你可以用很多方法来做。例如:
(unsigned int)a==(unsigned int)0x8000000
或(\uu int64)a==(\uu int64)0x8000000
或甚至是疯狂的(char*)a==(char*)0x8000000
或任何其他方式,只要您维护以下规则:
不降级编码(不要减少所需的位数)。Like(char)a==(char)0x8000000
不正确,因为您将32位降级为8位
必须为==运算符的左侧和右侧提供相同的上下文。如(char*)a==(无符号短)0x8000000
不正确,将产生错误/警告
我想再举一个例子,说明编码和意义之间的区别有多重要
char a = -7;
bool b = (a==-7) ? true : false;
'b'
的结果是什么?答案会让你震惊:它是未定义的。
一些编译器(通常是Microsoft visual studio)将编译一个程序,b将获得true
,而在Android NDK编译器上,b将获得false
。
原因是Android NDK将“char
”类型视为“unsigned char
”,而Visual studio将“char
”类型视为“signed char
”。因此在Android手机上,-7的编码实际上是249的意思,并不等于(int)-7的意思。
解决此问题的正确方法是将“a”专门定义为有符号字符:
signed char a = -7;
bool b = (a==-7) ? true : false;
“但是为什么编译器假设我想要一个正数”-因为你没有使用减号?!我刚刚测试了:警告:有符号和无符号整数表达式之间的比较[-Wsign compare]if(a=-0x8000000)
所以它仍然在抱怨是的,文本太大,无法放入有符号的int
中,因此编译器将其设置为无符号的
。等号右侧的类型不是由左侧的类型决定的。您是否有关于大小错误无符号的参考,或者这是个人意见?@StillLearning:of course我有一个强烈的观点(基于简单逻辑的推理已经成熟)认为这是一个错误。我不是唯一一个这样认为的人(请参阅).无符号的
不是一个“非负整数”,但它更像一个位掩码。容器大小无符号并不是因为它是逻辑的(它不是)但由于历史上的一次事故,可追溯到普通CPU为16位时(顺便说一句,我甚至在当时就犯了一个错误)你提供了一个很好的答案,但我不喜欢把你的个人观点放在中间。这对新的人来说是误导的。请删除那个部分。如果你不能证明它是错误的,你的答案是不恰当的。@ SistLoe:我通过历史意外错误地将< <代码> < <代码> > <代码> >(即使这实际上是一个错误;-))。还添加了一些解释,说明为什么在数量上使用无符号
通常是一个坏主意。我认为这样更好-更喜欢历史原因
,但仍然比错误
好。我不介意个人意见,只要清楚说明。将我的反对票改为赞成票。:-)@MatteoItalia有两种类型的工程师,一种是让事情顺利进行的工程师,另一种是花时间在实际工作上的工程师
signed char a = -7;
bool b = (a==-7) ? true : false;