【问题标题】:What happens if we assign a negative int into an unsigned int如果我们将负 int 分配给 unsigned int 会发生什么
【发布时间】:2014-06-30 10:07:41
【问题描述】:

这是代码:目标是判断所有数组成员的总和是正数还是负数。我知道 unsigned int 是一个错误,因为我想看看它会打印什么。所以问题是为什么它打印负数,我的意思是,将负 int 分配给 unsigned int 正在做什么。

#include <stdio.h>
#define ARR_SIZE 5
int main() {
int array[ARR_SIZE] = {1,-2,3,4,-5};
unsigned sum;
int i;
for ( i = 0, sum=0; i < ARR_SIZE; i++ )
        sum += array[i];
if( sum > -1 ) printf ("non-negative");
else printf ("negative");
return 0;
}

【问题讨论】:

  • 无符号整数溢出是根据 CHAR_BIT * sizeof(unsigned) 的模 2 定义的。
  • 注意到将负值分配给无符号变量的可能性是不寻常的。在这种情况下发生的隐式转换完全由 C 语言定义。根据模运算规则将值带入目标无符号类型的范围。模等于 2^N,其中 N 是无符号接收者中的值位数。这就是它在 C 中的一贯做法。
  • 您的编译器应该发出警告,表明您正在比较行 if( sum &gt; -1 ) … 的不同符号的表达式(-1 的类型为 intsumunsigned int)。如果没有,请在进一步努力之前找到如何启用此警告。

标签: c


【解决方案1】:

由于“sum”是无符号类型,因此“-1”也被转换为无符号类型(见下文)。这会导致比较一个非常大的数字(多大取决于机器)。

所以在纸上试试这个转换:

-1 转换为二进制数(尝试仅使用 2 个字节),然后将该二进制数转换为无符号数。确切的数字取决于机器(取决于您的 int 大小),但基本上您将 sum 与一个非常大的数字进行比较,因此您看到的结果。

委员会草案 — 2011 年 4 月 12 日

6.3.1.8 常用算术转换

首先,如果任一操作数对应的实数类型为 long double,则另一个 操作数在不改变类型域的情况下被转换为对应的实类型为 long double 的类型。

否则,如果任一操作数对应的实数类型为双精度,则另一 操作数在不改变类型域的情况下被转换为一个类型 对应的实数类型是double。

否则,如果任一操作数对应的实数类型为浮点数,则另一 操作数在不改变类型域的情况下被转换为一个类型 对应的真实类型是浮点数。 62)

否则,整数提升将在两个操作数上执行。然后 以下规则适用于提升的操作数: 如果两个操作数的类型相同,则无需进一步转换。

否则,如果两个操作数都具有有符号整数类型或都具有无符号 整数类型,具有较小整数转换等级类型的操作数是 转换为具有更高等级的操作数的类型。

相关部分:

否则,如果无符号整数类型的操作数的秩大于或等于另一个操作数类型的秩,则将有符号整数类型的操作数转换为无符号整数类型的操作数的类型。

否则,如果有符号整数类型的操作数的类型可以表示无符号整数类型的操作数的所有值,则将无符号整数类型的操作数转换为有符号整数类型的操作数的类型输入。

否则,两个操作数都转换为无符号整数类型,对应有符号整数类型的操作数。

【讨论】:

    【解决方案2】:

    有符号和无符号的区别完全在于开发者的头脑。对于计算机而言,数字只是在 PC(程序计数器)恰好指向的内存中遇到某些位模式时应用某些规则的位模式。

    因此,如果您将 -1 分配给 16 位变量,则内存中的位模式将是 1111 1111 1111 1111(每个位都将是 1 - 我对 32 位变量太懒了),无论是否变量有符号或无符号。

    编译器应该抱怨sum &gt; -1 条件,因为比较没有意义。

    作为人类,您期望 sum 始终为正,因此 is 条件始终为真。

    但编译器会将-1 转换为无符号(见下文),然后进行比较。 -1 为您提供给定位数可以表示的最大可能无符号数 -> 比较总是错误的,因为没有比这更大的了。

    所以你总是得到negative 作为输出,因为你头脑中的模型是错误的。

    根据 C99:在类型相同大小的二进制表达式中,有符号值转换为无符号值。如果带符号的值不能用无符号类型表示(例如 -1),则“通过在新的 [无符号] 类型中可以表示的最大值重复加或减 1 来转换该值,直到该值在新类型的范围。”

    感谢JeremyP

    【讨论】:

    • 其实sum &gt; -1 有一个明确的含义,只是它不太可能是程序员的意思。这不是非此即彼的情况。
    • @PascalCuoq:没错,但这会让它更难理解。
    • 你认为说它是两种可能性之一比说只有一种可能发生更简单?
    • 您的回答非常模棱两可'sum 总是肯定的(所以这总是正确的)'......好吧,sum 总是肯定的,但这不是真的。我知道你知道你在说什么,但你的解释有点令人困惑......尤其是这句话。
    • @PascalCuoq:我编辑了我的答案以更清楚地表明错误是人类在阅读代码时的期望与计算机将执行的操作之间的不匹配。
    【解决方案3】:

    2 的 -1 的补码表示是 1111 1111 1111 1111(假设无符号的大小是两个字节) 等于 65535

    在您的情况下,您将结果与 65535 进行比较,因为 sum

    【讨论】:

      猜你喜欢
      • 2011-11-01
      • 2019-10-07
      • 1970-01-01
      • 2017-05-07
      • 1970-01-01
      • 1970-01-01
      • 2014-08-02
      • 2019-09-08
      • 1970-01-01
      相关资源
      最近更新 更多