C:如何将2 32位无符号整数的结果保存为有符号整数

时间:2015-09-21 11:31:13

标签: c

我有以下代码,将结果保存为32位有符号整数和64位有符号整数。

当我用2147483647(有符号32位整数的最大允许值)减去0时,使用32位有符号整数会导致问题,所以正确的方法应该是使用64位有符号整数,我应该将无符号32位强制转换为带符号64咬得到想要的答案。这是正确的方法吗?

#include <stdio.h>
#include <string.h>
#include <stdint.h>

int main(void)
{
    int32_t fig32;
    int64_t fig64;
    uint32_t peak_seq = 2480694779;
    uint32_t pkt_seq = 2480694780;
    uint32_t zero_seq = 0;

    fig32 = peak_seq - pkt_seq;
    fig64 = peak_seq - pkt_seq;

    printf("\n 32 ans : %d, 64 ans is %ld\n", fig32, fig64);

    fig32 = zero_seq - pkt_seq;
    fig64 = zero_seq - pkt_seq;

    printf("\n 32 ans : %d, 64 ans is %ld\n", fig32, fig64);

    fig64 = (int64_t)peak_seq - (int64_t)pkt_seq;
    printf("\n fix for (peak - pkt) 64 ans is %ld\n", fig64);

    fig64 = (int64_t)zero_seq - (int64_t)pkt_seq;
    printf("\n fix for (zero - pkt) 64 ans is %ld\n", fig64);
}

当我运行此程序时,我得到以下输出

 32 ans : -1, 64 ans is 4294967295

 32 ans : 1814272516, 64 ans is 1814272516

 fix for (peak - pkt) 64 ans is -1

 fix for (zero - pkt) 64 ans is -2480694780
  1. 在第一行中为什么64位的答案是4294967295而不是 -1?
  2. 将所有无符号32位整数强制转换为64位符号 解决这个问题的唯一方法是什么?

2 个答案:

答案 0 :(得分:1)

首先,在任何C表达式x = y + z;中,用于计算y + z的类型与x的类型无关。任何计算中使用的类型取决于特定运算符的操作数类型。

在您的情况下,用于计算peak_seq - pkt_seq的类型与您在何处存储结果无关。由于两个操作数都是uint32_t类型(并且因为int在任何机器上可能不大于32位),因此操作在uint32_t类型上执行。结果是uint32_t类型。

由于操作的两个操作数都是无符号类型,因此它会下溢到4294967295.因此,此代码中peak_seq - pkt_seq的结果始终为(uint32_t)4294967295,或者如果您将为0xFFFFFFFF。

  

在第一行中为什么64位的答案是4294967295而不是-1?

当您尝试将此结果存储到int32_t时,它会根据实现定义的行为进行转换,在这种情况下,您将获得0xFFFFFFFF的二进制补码版本-1。

但是当你尝试在int64_t中恢复结果时,它很合适并且值不会改变。

  

将所有无符号32位整数强制转换为64位有符号解决此问题的唯一方法吗?

如果您需要签名号码,请使用签名号码。您发现代码结果奇怪的唯一原因是,如果您错误地认为两个无符号操作数将为您提供签名结果。

作为旁注,在打印int32_t时,您应使用printf("%" PRId, fig32)并使用int64_t使用PRId64(inttypes.h)。

答案 1 :(得分:1)

因为C规范要求对于unsigned int,溢出使用模数2 n (其中n是int类型的大小)。因此,peak_seq - pkt_seq会给出一个带有正值 FFFFFFFF4294967295的无符号整数。当您将其影响到int64_t或uint64_t变量时,通常会4294967295。当你影响if一个有符号的int变量时,结果是依赖于实现的,但对于常见的实现(补充到2),它给出-1 =&gt; fig32 = -1,很好。

你有2种方法可以获得-1。一个是依赖于实现的,而另一个是完美定义的。

  • 完美定义:您必须将您的值转换为能够代表它们的签名类型,此处int64_t是您的最佳选择
  • 依赖于实现:影响2 uint32_t与签名int32_t之间的差异,它将对当前实现起作用,然后才将其转换为int64_t。第一个操作应该给-1(作为int32_t),它将被正确地转换为-1 int64_t