繁体   English   中英

减去两个无符号的32位整数并分配给64位有符号整数

[英]subtracting two unsigned 32-bit integers and assign to 64-bit signed integer

目标是得到(-1)作为最终结果。

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

int main()
{

    uint32_t us32Var1, us32Var2;
    int32_t s32Var1;
    int64_t s64Var1;

    us32Var1 = 0;
    us32Var2 = 1;
    printf("(1) us32Var1 = %u(0x%08x), us32Var2 = %u(0x%08x)\n", us32Var1, us32Var1, us32Var2, us32Var2);

    s32Var1 = us32Var1 - us32Var2; //0xffffffff (-1)
    printf("(2) s32Var1 = us32Var1 - us32Var2, s32Var1 = %d(0x%08x)\n", s32Var1, s32Var1);

    s64Var1 = us32Var1 - us32Var2;  //0x00000000ffffffff  (expect it's -1, but the result > 0)
    printf("(3) s64Var1 = us32Var1 - us32Var2, s64Var1 = %ld(0x%016lx)\n", s64Var1, s64Var1);

    s64Var1 = (int64_t)(us32Var1 - us32Var2);  //0x00000000ffffffff  (expect it's -1, but the result > 0)
    printf("(4) s64Var1 = (int64_t)(us32Var1 - us32Var2), s64Var1 = %ld(0x%016lx)\n", s64Var1, s64Var1);

    s64Var1 = (int64_t)us32Var1 - us32Var2;  //0xffffffffffffffff  (-1)
    printf("(5) s64Var1 = (int64_t)us32Var1 - us32Var2, s64Var1 = %ld(0x%016lx)\n", s64Var1, s64Var1);

    us32Var1 = -1; //us32Var1 = 0xffffffff, UINT32_MAX
    s64Var1 = (int64_t)us32Var1; //0x00000000ffffffff  (expect it's -1, but the result > 0)
    printf("(6) s64Var1 = (int64_t)us32Var1, s64Var1 = %ld(0x%016lx)\n", s64Var1, s64Var1);

    s64Var1 = (int32_t)us32Var1; //0xffffffffffffffff  (-1 !)
    printf("(7) s64Var1 = (int32_t)us32Var1, s64Var1 = %ld(0x%016lx)\n", s64Var1, s64Var1);
    return 0;
}

对于上述程序(每行都有编号),有人可以解释

  • 为什么(2)按预期工作,但不适用于(3)? ALU的算术或微步骤是什么?
  • (4)和(5)之间有什么区别
  • 为什么(7)工作而(6)失败

(2)工作,但可能不是你的想法。 us32Var1-us32Var1将产生无符号值0xFFFFFFFFU (模运算),并且对s32Var1的赋值将其转换为带符号的32位值,即-1 在(3)中,赋值也转换它,但现在转换为64位有符号值,并且大到足以包含0xFFFFFFFFU ,因此它保持正值。 (4)和(5)之间的区别在于,在(4)中,减法发生在32位,然后转换为64位。 在(5)中,其中一个操作数首先被转换为64位,因此减法为64位,因此另一个操作数也被隐式转换为64位。 (6)类似于(2),32位中的有符号值-1在分配给us32Var1被转换为无符号32位,因此结果为0xFFFFFFFFU这很容易适合s64Var1 ,因此它保持为正。 在(7)中, 0xFFFFFFFFU首先被转换为有符号的32位,因此为-1 ,然后将其分配给有符号的64位,从而得到-1

我希望这有帮助。

所以回答下面的问题。 在(3)中,减法仍然以32位无符号进行,因此结果为0xFFFFFFFFU因为-1不能用无符号表示。 这个32位无符号结果被转换为带符号的64位,它可以精确地表示0xFFFFFFFFU ,因此这就是结果。

对于(7),赋值确实执行符号扩展,因为右侧是32位且为负。 注意,变量us32Var1包含(当然)正值,但它被转换为32位有符号值,不能表示0xFFFFFFFFU ,因此它被转换为-1

  • 为什么(2)按预期工作,但不适用于(3)? ALU的算术或微步骤是什么?

嗯,它的工作方式与期望的一样。 计算无符号32的结果,然后将无符号值转换为有符号,因此它自然是零扩展的。

  • (4)和(5)之间有什么区别?

(4)与我上面描述的相同,并且(5)最终计算0LL-1LL,其实际上是〜0LL。 它可能会产生什么其他结果? 值得注意的是,在机器内部,有符号和无符号数字之间没有太大区别。 完全相同的ALU用于有符号和无符号操作。 除了少数例外, 签名无符号的区别是在解释结果时以及在决定是否签名扩展时所做的,而不是在实际执行算术ALU操作时所做的。

  • 为什么(7)工作而(6)失败?

我不确定我会说(6) 失败 ,确切地说。 您将无符号值转换为有符号值,因此它自然地对其进行零扩展。 在(7)中,您将带符号的32值转换为64位,因此它自然是符号扩展的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM