7

我无法理解如何比较两个整数,其中一个是 unsigned int32 而另一个是有符号 int32 工作。让我们考虑这个简单的程序:

#include <stdint.h>

int main()
{
    uint32_t a1 = UINT32_MAX;
    int32_t b1 = (int32_t)a1;

    if (a1 == b1)
        printf("Equal");
    else
        printf("Not equal");

    return 0;
}

在这种情况下,a1超出了有符号的 32 位整数范围,所以正如我在调试时确认的那样,在它被转换后,b1等于-1. 但是它仍然打印“Equal”,而这些值显然不一样。它是由什么引起的?

4

3 回答 3

6

正如您所做的那样,到有符号整数类型的超出范围转换是实现定义的。

在您可能遇到的大多数实现中,将 a 的最大值转换为uint32_taint32_t意味着保留位模式并将其视为有符号值。这意味着它b1被分配了值-1。

然后比较a1andb1时,将应用通常的算术转换。这些在C 标准的第 6.3.1.8 节中有详细说明:

如果两个操作数具有相同的类型,则不需要进一步转换。

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

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

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

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

在这种情况下,突出显示的部分是适用的,因为uint32_tint32_t具有相同的等级,所以 的值b1被转换为 type uint32_t

当为无符号类型转换超出范围的值时,这是通过在数值上重复地增加或减去无符号类型的最大值,直到该值在范围内。这实际上意味着源值的任何多余字节都将被截断,剩下的将被视为无符号值。

这种转换在C 标准的第 6.3.1.3 节中有详细说明:

1当整数类型的值转换为除 以外的其他整数类型_Bool时,如果该值可以用新的类型表示,则保持不变。

2否则,如果新类型是无符号的,则在新类型可以表示的最大值的基础上反复加减一,直到该值在新类型的范围内。

3否则,新类型是有符号的,值不能在其中表示;结果是实现定义的或引发了实现定义的信号

在这种情况下,第 3 段适用于您第一次分配a1给 时b1,然后第 2 段适用于您进行比较并b1转换时。这意味着值 -1 被转换为 value UINT32_MAX,这就是比较结果为 true 的原因。

于 2019-11-12T23:27:43.840 回答
4

内置==函数只能比较相同类型的值。如果操作数的类型不同,则预先将它们转换为相同的类型。(有关如何选择此类型,请参阅cppreference 。)

在这种情况下,在执行b1比较之前转换为uint32_t

于 2019-11-12T23:18:53.667 回答
4

一般来说,无符号到有符号的转换现在是实现定义的(6.3.1.3)(这可能会在未来的 C 标准版本中改变)。

在实践中,整数将是二进制补码,并且任一方向的转换都是无操作的——相同的数据将根据二进制补码算法的工作方式进行不同的解释。

在您的情况下,相等性是由于通常的算术转换 (6.3.1.8)b1在比较中将带符号的符号在语义上转换为a1无符号类型引起的。

于 2019-11-12T23:25:17.567 回答