【问题标题】:Casting uint32_t to int32_t and comparing them afterwards将 uint32_t 转换为 int32_t 并在之后进行比较
【发布时间】:2019-11-12 23:13:29
【问题描述】:

我无法理解如何比较两个 int,其中一个是 unsigned int32 而另一个是signed 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”,而这些值显然不一样。是什么原因造成的?

【问题讨论】:

  • "检查 a1 值是否在有符号 32 位整数范围内。" --> in_range = a1 &lt;= INT32_MAX;

标签: c stdint


【解决方案1】:

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

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

当您比较 a1b1 时,通常的算术转换适用。这些在C standard 的第 6.3.1.8 节中有详细说明:

如果两个操作数的类型相同,则不再进行转换 需要。

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

否则,如果无符号整数类型的操作数有 等级大于或等于其他类型的等级 操作数,则带符号整数类型的操作数为 转换为无符号整数的操作数类型 输入。

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

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

高亮部分适用于这种情况,因为uint32_tint32_t 具有相同的等级,所以b1 的值被转换为类型uint32_t

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

C standard 的第 6.3.1.3 节详细说明了这种转换:

1 当一个整数类型的值转换为_Bool以外的其他整数类型时,如果该值可以用新的 类型,它是不变的。

2 否则,如果新类型是无符号的,则通过重复加减一的方式转换值 新类型可以表示的最大值 直到值在新类型的范围内。

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

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

【讨论】:

  • 好答案。迂腐:如果 int 是 64 位,则结果将是 "Not equal" ;-)
  • 您忘记了第一个摘录中的 first 行:“否则,对两个操作数都执行整数提升。规则应用于提升的操作数:" 如果 int 是 64 位,则此子句会将它们都转换为 int,然后“它们属于同一类型”
【解决方案2】:

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

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

在您的情况下,相等是由于 usual arithmetic conversions (6.3.1.8) 在比较中将带符号的 b1 语义转换为 a1 的无符号类型引起的。

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

    • 有什么方法可以检查 a1 的值在转换前后是否真的相同?我正在尝试检查 a1 值是否在有符号 32 位整数范围内。
    • @MLapaj 检查a1 &lt; (1U &lt;&lt; 31)
    猜你喜欢
    • 2013-06-09
    • 1970-01-01
    • 1970-01-01
    • 2023-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多