1

目标是得到 (-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)失败
4

2 回答 2

2

(2) 有效,但可能不是您想的那样。us32Var1-us32Var1将产生无符号值0xFFFFFFFFU(模算术)和赋值s32Var1将其转换为有符号的 32 位值,因此-1. 在 (3) 中,赋值也将其转换为 64 位有符号值,并且大到足以包含0xFFFFFFFFU,因此它保持为正。(4) 和 (5) 之间的区别在于,在 (4) 中,减法发生在 32 位中,然后转换为 64 位。在 (5) 中,一个操作数首先转换为 64 位,因此减法为 64 位,因此另一个操作数也隐式转换为 64 位。(6) 与 (2) 类似,-132 位的有符号值在赋值中被转换为无符号的 32 位,us32Var1因此结果0xFFFFFFFFU很容易满足s64Var1,所以它保持正数。在 (7)0xFFFFFFFFU中首先转换为有符号的 32 位,因此是-1,然后将其分配给有符号的 64 位,因此导致-1

我希望这有帮助。

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

对于 (7),赋值确实进行了符号扩展,因为右手边是 32 位并且是负数。请注意,该变量us32Var1(当然)包含一个正值,但它被转换为无法表示的 32 位有符号值,0xFFFFFFFFU因此它被强制转换为-1

于 2013-04-03T18:40:28.997 回答
2
  • 为什么(2)按预期工作,而不是(3)?ALU 的算术或微步是什么?

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

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

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

  • 为什么(7)有效而(6)失败?

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

于 2013-04-03T18:41:40.823 回答