【问题标题】:Unsigned and signed comparison无符号和有符号比较
【发布时间】:2010-08-02 04:03:20
【问题描述】:

这是非常简单的代码,

#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;
}

count的值为0,为什么?

【问题讨论】:

  • 顺便说一句,您应该使用std::endl 而不是将\n 插入到流中,因为std::endl 两者都是可移植的并确保输出立即显示。
  • @Ben: \n 一样便携;如果你现在特别想刷新流,你应该只使用endl
  • \n 是可移植的(它被转换为平台的换行序列),并且不承担立即刷新流的开销。你应该使用具有你想要的语义的那个:如果你想刷新流,使用endl,如果你只是想要一个换行符,使用\n
  • std::endl 等价于 "\n"

标签: c++


【解决方案1】:

&lt;= 的两个操作数必须提升为相同的类型。

显然他们被提升为unsigned int(我面前没有标准的规则,我会在一秒钟内查找)。由于(unsigned int)(-1) &lt;= u 为假,循环永远不会执行。

该规则可在标准的第 5 节(expr)第 10 段中找到,其中指出(我已突出显示适用于此处的规则):

许多期望算术或枚举类型的操作数的二元运算符会导致转换并以类似的方式产生结果类型。目的是产生一个通用类型,这也是结果的类型。 这种模式称为通常的算术转换,定义如下:

  • 如果任一操作数属于范围枚举类型 (7.2),则不执行任何转换;如果另一个操作数的类型不同,则表达式格式错误。
  • 如果任一操作数为 long double 类型,则另一个应转换为 long double。
  • 否则,如果任一操作数为双精度,则另一个应转换为双精度。
  • 否则,如果任一操作数为浮点数,则另一个应转换为浮点数。
  • 否则,应对两个操作数执行积分提升 (4.5)。 60 然后下面 规则应应用于提升的操作数:
  • 如果两个操作数的类型相同,则无需进一步转换。
  • 否则,如果两个操作数都是有符号整数类型或都具有无符号整数类型,则整数转换等级较小的操作数应转换为等级较大的操作数类型。
  • 否则,如果无符号整数类型的操作数的秩大于或等于另一个操作数类型的秩,则将有符号整数类型的操作数转换为无符号操作数的类型整数类型。
  • 否则,如果带符号整数类型的操作数的类型可以表示无符号整数类型的操作数类型的所有值,则将无符号整数类型的操作数转换为带符号整数类型的操作数的类型输入。
  • 否则,两个操作数都应转换为与带符号整数类型的操作数类型对应的无符号整数类型。

【讨论】:

    【解决方案2】:

    在比较(i &lt;= u)时,i升级为无符号整数,并在此过程中将-1转换为UINT_MAX。

    将负数转换为无符号整数会将 (UINT_MAX + 1) 加到该数字上,因此 -1 变为 UINT_MAX,-2 变为 UINT_MAX - 1,等等。

    如果您考虑一下,必须将一个转换为另一个才能进行比较,并且编译器通常会将有符号值转换为无符号值。当然,在这种情况下,将无符号值转换为有符号值会更有意义,但编译器不能仅仅根据您的意图决定遵循不同的规范。您应该在这里明确地将 unsigned int 转换为已签名(或一直保持签名)。

    【讨论】:

    • 您的规则无效。实际上是加了2**32,是UINT_MAX + 1,不是UINT_MAX - 1
    • WRT 你的新 cmets,从有符号到无符号的转换对于所有输入都是明确定义的,但是从无符号到有符号的转换可以调用实现定义的行为(这里不会,因为值u 是 10,适合 int)。
    • 是的,当我建议使用或转换为 u 的带符号整数时,假设 u 保持在带符号整数的允许范围内。如果你可能超过这个并且你真的需要无符号,你将不得不重新考虑一下代码——比如不要以负一开始i
    【解决方案3】:

    因为 -1 被强制转换为无符号整数,所以永远不会执行 for 循环代码。

    尝试使用 -Wall -Wextra 进行编译,这样您就可以获得相应的警告(如果到目前为止还没有收到警告,则使用 g++ 进行编译)

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

    【讨论】:

    • 谢谢,我只想问你一件事,我会给我的问题提供链接,请告诉我为什么他们降低我的分数或者他们投反对票好吗?我想拥有良好的声誉并尝试发布好的问题,但他们降低了它
    • @davit:您的另一个问题被否决了,因为编译器确切地告诉您出了什么问题(您缺少分号),但您在此处发布了您的问题,甚至没有尝试自己解决问题。
    【解决方案4】:

    这是因为i 在比较之前被提升为无符号值。这会将其设置为 UINT_MAX 的值,在 32 位机器上等于 4294967295。所以你的循环本质上是一样的:

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

    【讨论】:

      【解决方案5】:

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

      【讨论】:

      • 不,在二进制补码表示中-1 存储为全1。但实际的表示并不重要,因为 C++ 标准定义了从有符号整数类型到无符号整数类型的转换在模块 base-N 算术中是全等的。
      • 虽然这在符号幅度系统上是正确的,但现在非常罕见。当前最合理的系统对整数使用 2 的补码,在这种情况下,-1 将由所有设置为 1 的位表示(在这种情况下,从有符号到无符号的转换根本不需要改变数据,只需改变它的方式解释)。
      • @Jerry:符号量级并不罕见。 IEEE 754 需要它。几乎每台计算机都使用二进制补码整数和符号幅度浮点表示。
      • @Ben:是的,如果您费心阅读第二句话就很明显了,我说的是整数,而不是浮点数。
      • @Jerry:我明白这一点。但我不希望某个计算机工程专业的学生看到这个帖子并说“我不会费心去学习符号幅度算法的工作原理,因为反正没人用它”。
      猜你喜欢
      • 2014-01-28
      • 2011-07-21
      • 1970-01-01
      • 2016-08-07
      • 1970-01-01
      • 1970-01-01
      • 2021-10-31
      • 1970-01-01
      相关资源
      最近更新 更多