有符号和无符号整数表达式之间的警告比较

我目前正在通过 加速 C + + 工作,并在练习2-3中遇到了一个问题。

程序 的一个快速概述-该程序基本上接受一个名称,然后在一个星号框架内显示一个问候语-即 Hello!被 * 包围着。

练习 -在示例程序中,作者使用 const int来确定问候语和星号之间的空白。然后,他们要求读者,作为练习的一部分,要求用户输入他们想要的填充物有多大。

所有这些看起来很容易,我继续要求用户两个整数(int) ,并存储它们和改变程序使用这些整数,删除使用的作者,虽然我得到以下警告;

练习2-3. cpp: 46: 警告: 有符号和无符号整数表达式之间的比较

经过一些研究,这似乎是因为代码试图比较上述整数(int)之一的 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

上面是相关的代码片段,cstring::size_type类型的,因为我们不知道问候语可能有多长——但是为什么我现在遇到这个问题,当作者的代码在使用 const int时没有遇到这个问题?除此之外-任何人谁可能已经完成了 加速 C + + -这将在本书后面解释?

我在 Linux Mint 上通过 Geany 使用 g + + ,如果这有帮助或有影响的话(正如我读到的那样,在确定什么是 string::size_type时,它可以起到作用)。

282646 次浏览

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

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();
}

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

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.

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

(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'.

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

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.

What makes this example more complicated is that the different padding variables (padsides and padtopbottom), as well as all counters, must also be changed to 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:

    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.

or use this header library and write:

// |notEqaul|less|lessEqual|greater|greaterEqual
if(sweet::equal(valueA,valueB))

and don't care about signed/unsigned or different sizes

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.

8-bits: -1 signed is the same bits as 255 unsigned 16-bits: -1 signed is the same bits as 65535 unsigned etc.

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.

Thus, you have to write the above if, to remove the signed/unsigned warning as:

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.