C++ 警告 - 有符号和无符号整数表达式之间的比较
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3660901/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
A warning - comparison between signed and unsigned integer expressions
提问by Tim Harrington
I am currently working through Accelerated C++and have come across an issue in exercise 2-3.
我目前正在使用Accelerated C++,并且在练习 2-3 中遇到了一个问题。
A quick overview of the program- the program basically takes a name, then displays a greeting within a frame of asterisks - i.e. Hello ! surrounded framed by *'s.
程序的快速概览- 该程序基本上取一个名称,然后在星号框架内显示问候语 - 即 Hello !由 * 包围。
The exercise- In the example program, the authors use const int
to determine the padding (blank spaces) between the greeting and the asterisks. They then ask the reader, as part of the exercise, to ask the user for input as to how big they want the padding to be.
练习- 在示例程序中,作者const int
用来确定问候语和星号之间的填充(空格)。然后,作为练习的一部分,他们要求读者询问用户他们希望填充有多大。
All this seems easy enough, I go ahead ask the user for two integers (int
) and store them and change the program to use these integers, removing the ones used by the author, when compiling though I get the following warning;
所有这一切看起来都很简单,我继续要求用户提供两个整数 ( int
) 并存储它们并更改程序以使用这些整数,删除作者使用的那些,但在编译时我收到以下警告;
Exercise2-3.cpp:46: warning: comparison between signed and unsigned integer expressions
练习 2-3.cpp:46:警告:有符号和无符号整数表达式之间的比较
After some research it appears to be because the code attempts to compare one of the above integers (int
) to a string::size_type
, which is fine. But I was wondering - does this mean I should change one of the integers to unsigned int
? Is it important to explicitly state whether my integers are signed or unsigned?
经过一些研究,这似乎是因为代码试图将上述整数之一 ( int
) 与 a 进行比较string::size_type
,这很好。但我想知道 - 这是否意味着我应该将其中一个整数更改为 unsigned int
?明确说明我的整数是有符号还是无符号很重要吗?
cout << "Please enter the size of the frame between top and bottom you would like ";
int padtopbottom;
cin >> padtopbottom;
cout << "Please enter size of the frame from each side you would like: ";
unsigned int padsides;
cin >> padsides;
string::size_type c = 0; // definition of c in the program
if (r == padtopbottom + 1 && c == padsides + 1) { // where the error occurs
Above are the relevant bits of code, the c
is of type string::size_type
because we do not know how long the greeting might be - but why do I get this problem now, when the author's code didn't get the problem when using const int
? In addition - to anyone who may have completed Accelerated C++- will this be explained later in the book?
以上是代码的相关位,则c
是类型的string::size_type
,因为我们不知道的问候可能有多长-但为什么我现在得到这个问题,在使用时,笔者的代码没有得到这个问题const int
?此外——对于可能已经完成加速 C++ 的任何人——这本书后面会解释吗?
I am on Linux Mint using g++ via Geany, if that helps or makes a difference (as I read that it could when determining what string::size_type
is).
我在 Linux Mint 上通过 Geany 使用 g++,如果这有帮助或有所不同(正如我在确定什么时读到的那样string::size_type
)。
回答by Kristopher Johnson
It is usually a good idea to declare variables as unsigned
or size_t
if they will be compared to sizes, to avoid this issue. Whenever possible, use the exact type you will be comparing against (for example, use std::string::size_type
when comparing with a std::string
's length).
将变量声明为unsigned
或size_t
是否将它们与大小进行比较通常是一个好主意,以避免此问题。只要有可能,请使用您将与之比较的确切类型(例如,std::string::size_type
在与 astd::string
的长度进行比较时使用)。
Compilers give warnings about comparing signed and unsigned types because the ranges of signed and unsigned ints are different, and when they are compared to one another, the results can be surprising. If you have to make such a comparison, you should explicitly convert one of the values to a type compatible with the other, perhaps after checking to ensure that the conversion is valid. For example:
编译器会发出有关比较有符号和无符号类型的警告,因为有符号和无符号整数的范围不同,并且当它们相互比较时,结果可能会令人惊讶。如果您必须进行这样的比较,您应该将其中一个值显式转换为与另一个值兼容的类型,也许在检查以确保转换有效之后。例如:
unsigned u = GetSomeUnsignedValue();
int i = GetSomeSignedValue();
if (i >= 0)
{
// i is nonnegative, so it is safe to cast to unsigned value
if ((unsigned)i >= u)
iIsGreaterThanOrEqualToU();
else
iIsLessThanU();
}
else
{
iIsNegative();
}
回答by eric
I had the exact same problem yesterday working through problem 2-3 in Accelerated C++. The key is to change all variables you will be comparing (using Boolean operators) to compatible types. In this case, that means string::size_type
(or unsigned int
, but since this example is using the former, I will just stick with that even though the two are technically compatible).
昨天我在 Accelerated C++ 中解决了问题 2-3 时遇到了完全相同的问题。关键是将您将比较(使用布尔运算符)的所有变量更改为兼容类型。在这种情况下,这意味着string::size_type
(或unsigned int
,但由于此示例使用的是前者,因此即使两者在技术上兼容,我也会坚持使用)。
Notice that in their original code they did exactly this for the c counter (page 30 in Section 2.5 of the book), as you rightly pointed out.
请注意,正如您正确指出的那样,在他们的原始代码中,他们对 c 计数器(本书第 2.5 节中的第 30 页)完全做到了这一点。
What makes this example more complicated is that the different padding variables (padsides and padtopbottom), as well as all counters, must alsobe changed to string::size_type
.
使此示例更加复杂的是,不同的填充变量(padsides 和 padtopbottom)以及所有计数器也必须更改为string::size_type
.
Getting to your example, the code that you posted would end up looking like this:
以您的示例为例,您发布的代码最终将如下所示:
cout << "Please enter the size of the frame between top and bottom";
string::size_type padtopbottom;
cin >> padtopbottom;
cout << "Please enter size of the frame from each side you would like: ";
string::size_type padsides;
cin >> padsides;
string::size_type c = 0; // definition of c in the program
if (r == padtopbottom + 1 && c == padsides + 1) { // where the error no longer occurs
Notice that in the previous conditional, you would get the error if you didn't initialize variable r as a string::size_type
in the for
loop. So you need to initialize the for loop using something like:
请注意,在前面的条件中,如果您没有string::size_type
在for
循环中将变量 r 初始化为 a,则会出现错误。因此,您需要使用以下内容初始化 for 循环:
for (string::size_type r=0; r!=rows; ++r) //If r and rows are string::size_type, no error!
So, basically, once you introduce a string::size_type
variable into the mix, any time you want to perform a boolean operation on that item, all operands must have a compatible type for it to compile without warnings.
所以,基本上,一旦你string::size_type
在混合中引入一个变量,任何时候你想对那个项目执行布尔运算,所有的操作数都必须有一个兼容的类型,它才能在没有警告的情况下编译。
回答by AndreasT
The important difference between signed and unsigned ints is the interpretation of the last bit. The last bit in signed types represent the sign of the number, meaning: e.g:
有符号整数和无符号整数之间的重要区别在于最后一位的解释。有符号类型的最后一位代表数字的符号,意思是:例如:
0001 is 1 signed and unsigned 1001 is -1 signed and 9 unsigned
0001 是 1 有符号和无符号 1001 是 -1 有符号和 9 无符号
(I avoided the whole complement issue for clarity of explanation! This is not exactly how ints are represented in memory!)
(为清楚起见,我避免了整个补码问题!这并不是整数在内存中的表示方式!)
You can imagine that it makes a difference to know if you compare with -1 or with +9. In many cases, programmers are just too lazy to declare counting ints as unsigned (bloating the for loop head f.i.) It is usually not an issue because with ints you have to count to 2^31 until your sign bit bites you. That's why it is only a warning. Because we are too lazy to write 'unsigned' instead of 'int'.
您可以想象,知道与 -1 还是 +9 进行比较会有所不同。在许多情况下,程序员只是懒得将计数 int 声明为无符号(使 for 循环头 fi 膨胀)这通常不是问题,因为对于 int,您必须计数到 2^31,直到您的符号位咬住您为止。这就是为什么它只是一个警告。因为我们懒得写 'unsigned' 而不是 'int'。
回答by Martin York
At the extreme ranges, an unsigned int can become larger than an int.
Therefore, the compiler generates a warning. If you are sure that this is not a problem, feel free to cast the types to the same type so the warning disappears (use C++ cast so that they are easy to spot).
在极端范围内,unsigned int 可能比 int 大。
因此,编译器会生成警告。如果您确定这不是问题,请随意将类型强制转换为相同类型,以便警告消失(使用 C++ 强制转换,以便它们易于发现)。
Alternatively, make the variables the same type to stop the compiler from complaining.
I mean, is it possible to have a negative padding? If so then keep it as an int. Otherwise you should probably use unsigned int and let the stream catch the situations where the user types in a negative number.
或者,使变量具有相同的类型以阻止编译器抱怨。
我的意思是,是否可以使用负填充?如果是这样,则将其保留为 int。否则,您可能应该使用 unsigned int 并让流捕获用户键入负数的情况。
回答by burner
or use this header libraryand write:
或使用此头文件库并编写:
// |notEqaul|less|lessEqual|greater|greaterEqual
if(sweet::equal(valueA,valueB))
and don't care about signed/unsigned or different sizes
并且不关心签名/未签名或不同的大小
回答by Gregg Wonderly
The primary issue is that underlying hardware, the CPU, only has instructions to compare two signed values or compare two unsigned values. If you pass the unsigned comparison instruction a signed, negative value, it will treat it as a large positive number. So, -1, the bit pattern with all bits on (twos complement), becomes the maximum unsigned value for the same number of bits.
主要问题是底层硬件 CPU 只有比较两个有符号值或比较两个无符号值的指令。如果向无符号比较指令传递一个有符号的负值,它将把它当作一个大的正数。因此,-1,所有位都打开(二进制补码)的位模式,成为相同位数的最大无符号值。
8-bits: -1 signed is the same bits as 255 unsigned 16-bits: -1 signed is the same bits as 65535 unsigned etc.
8 位:-1 有符号与 255 位无符号 16 位相同:-1 有符号与 65535 无符号等位相同。
So, if you have the following code:
因此,如果您有以下代码:
int fd;
fd = open( .... );
int cnt;
SomeType buf;
cnt = read( fd, &buf, sizeof(buf) );
if( cnt < sizeof(buf) ) {
perror("read error");
}
you will find that if the read(2) call fails due to the file descriptor becoming invalid (or some other error), that cnt will be set to -1. When comparing to sizeof(buf), an unsigned value, the if() statement will be false because 0xffffffff is not less than sizeof() some (reasonable, not concocted to be max size) data structure.
您会发现,如果 read(2) 调用因文件描述符无效(或某些其他错误)而失败,则 cnt 将设置为 -1。与 sizeof(buf),一个无符号值相比,if() 语句将是错误的,因为 0xffffffff 不小于 sizeof() 一些(合理的,不是炮制为最大大小)数据结构。
Thus, you have to write the above if, to remove the signed/unsigned warning as:
因此,您必须编写上述 if,以删除签名/未签名警告:
if( cnt < 0 || (size_t)cnt < sizeof(buf) ) {
perror("read error");
}
This just speaks loudly to the problems.
这只是大声说明问题。
1. Introduction of size_t and other datatypes was crafted to mostly work,
not engineered, with language changes, to be explicitly robust and
fool proof.
2. Overall, C/C++ data types should just be signed, as Java correctly
implemented.
If you have values so large that you can't find a signed value type that works, you are using too small of a processor or too large of a magnitude of values in your language of choice. If, like with money, every digit counts, there are systems to use in most languages which provide you infinite digits of precision. C/C++ just doesn't do this well, and you have to be very explicit about everything around types as mentioned in many of the other answers here.
如果您的值太大而无法找到有效的有符号值类型,则您使用的处理器太小或所选语言中的值数量太大。如果像金钱一样,每个数字都很重要,那么在大多数语言中都有一些系统可以为您提供无限位数的精度。C/C++ 只是做得不好,你必须非常明确地了解这里的许多其他答案中提到的关于类型的一切。