简体   繁体   English

未签名和签名的比较

[英]Unsigned and signed comparison

Here is very simple code, 这是非常简单的代码,

#include <iostream>
using namespace std;
int main() {
    unsigned int u=10;
    int i;
    int count=0;
    for (i=-1;i<=u;i++){
        count++;
    }
    cout<<count<<"\n";
    return 0;
}

The value of count is 0. Why? count的值是0.为什么?

Both operands of <= have to be promoted to the same type. 两个操作数<=必须提升为相同的类型。

Evidently they are promoted to unsigned int (I don't have the rule from the standard in front of me, I'll look it up in a second). 显然他们被提升为unsigned int (我没有在我面前的标准规则,我会在一秒钟内查找)。 Since (unsigned int)(-1) <= u is false, the loop never executes. 由于(unsigned int)(-1) <= u为false,因此循环永远不会执行。

The rule is found in section 5 (expr) of the standard, paragraph 10, which states (I've highlighted the rule which applies here): 该规则见标准第10节第5节(expr),其中指出(我强调了适用于此的规则):

Many binary operators that expect operands of arithmetic or enumeration type cause conversions and yield result types in a similar way. 许多期望算术或枚举类型的操作数的二元运算符会以类似的方式引起转换并产生结果类型。 The purpose is to yield a common type, which is also the type of the result. 目的是产生一个通用类型,它也是结果的类型。 This pattern is called the usual arithmetic conversions, which are defined as follows: 这种模式称为通常的算术转换,定义如下:

  • If either operand is of scoped enumeration type (7.2), no conversions are performed; 如果任一操作数具有作用域枚举类型(7.2),则不执行任何转换; if the other operand does not have the same type, the expression is ill-formed. 如果另一个操作数的类型不同,则表达式格式不正确。
  • If either operand is of type long double, the other shall be converted to long double. 如果任一操作数的类型为long double,则另一个操作数应转换为long double。
  • Otherwise, if either operand is double, the other shall be converted to double. 否则,如果任一操作数为double,则另一个操作数应转换为double。
  • Otherwise, if either operand is float, the other shall be converted to float. 否则,如果任一操作数是浮点数,则另一个操作数应转换为浮点数。
  • Otherwise, the integral promotions (4.5) shall be performed on both operands. 否则,应对两个操作数执行整体促销(4.5)。 60 Then the following rules shall be applied to the promoted operands: 60然后,以下规则应适用于提升的操作数:
  • If both operands have the same type, no further conversion is needed. 如果两个操作数具有相同的类型,则不需要进一步转换。
  • Otherwise, if both operands have signed integer types or both have unsigned integer types, the operand with the type of lesser integer conversion rank shall be converted to the type of the operand with greater rank. 否则,如果两个操作数都有有符号整数类型或两者都有无符号整数类型,则具有较小整数转换等级类型的操作数应转换为具有较大等级的操作数的类型。
  • Otherwise, if the operand that has unsigned integer type has rank greater than or equal to the rank of the type of the other operand, the operand with signed integer type shall be converted to the type of the operand with unsigned integer type. 否则,如果具有无符号整数类型的操作数的秩大于或等于另一个操作数的类型的秩,则具有有符号整数类型的操作数应转换为具有无符号整数类型的操作数的类型。
  • Otherwise, if the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type, the operand with unsigned integer type shall be converted to the type of the operand with signed integer type. 否则,如果具有有符号整数类型的操作数的类型可以表示具有无符号整数类型的操作数类型的所有值,则具有无符号整数类型的操作数应转换为具有有符号整数类型的操作数的类型。
  • Otherwise, both operands shall be converted to the unsigned integer type corresponding to the type of the operand with signed integer type. 否则,两个操作数都应转换为与带符号整数类型的操作数类型相对应的无符号整数类型。

During the comparison (i <= u) , i is upgraded to an unsigned integer, and in the process -1 is converted to UINT_MAX. 在比较期间(i <= u)i被升级为无符号整数,并且在该过程中-1被转换为UINT_MAX。

A conversion of a negative number to an unsigned int will add (UINT_MAX + 1) to that number, so -1 becomes UINT_MAX, -2 becomes UINT_MAX - 1, etc. 将负数转换为unsigned int会将(UINT_MAX + 1)添加到该数字,因此-1变为UINT_MAX,-2变为UINT_MAX - 1等。

If you think about it, one had to be converted to the other in order for the comparison to even work, and as a rule the compiler converts the signed value to unsigned. 如果你考虑它,必须将一个转换为另一个,以便比较甚至工作,并且通常编译器将签名值转换为unsigned。 In this case, of course, it'd make more sense to convert the unsigned value to signed instead, but the compiler can't just decide to follow a different spec based on what you intend. 在这种情况下,当然,将无符号值转换为有符号值更有意义,但编译器不能仅根据您的意图决定遵循不同的规范。 You should explicitly cast the unsigned int to signed (or just have it as signed all along) here. 你应该在这里明确地将unsigned int强制转换为signed(或者只是将其作为签名)。

Its because -1 is casted as an unsigned int, so the for loop code is never executed. 因为-1被转换为unsigned int,所以for循环代码永远不会被执行。

Try compiling with -Wall -Wextra so you can get the respective warnings (if not getting them so far, and compiling with g++) 尝试使用-Wall -Wextra进行编译,这样你就可以得到相应的警告(如果到目前为止没有得到它们,并用g ++编译)

http://en.wikipedia.org/wiki/Two's_complement http://en.wikipedia.org/wiki/Two's_complement

This is because i is promoted to an unsigned value before comparison. 这是因为在比较之前i被提升为无符号值。 This will set it to the value of UINT_MAX , which on a 32 bit machine equals to 4294967295 . 这将把它设置为UINT_MAX的值,它在32位机器上等于4294967295 So your loop is essentially the same as: 所以你的循环基本上与:

// will never run
for (i = 4294967295; i <= u; i++) {
    count++;
}

在一个整数以4个字节存储的系统中,我认为-1的值等于2147483649(1000 0000 0000 0000 0000 0000 0000 0001)的值 - 它是1,MSB设置为1表示它是负数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM