将unsignedint(通过负数)分配给signedlonglong时的意外值

我碰巧遇到了一个奇怪的问题,请看下面的代码:

#include <stdio.h>

int main() {
    unsigned char a = 10;
    unsigned int b = 10;

    long long x = -a;
    long long y = -b;

    printf("x = %lld, y = %lldn", x, y);
    return 0;
}

输出:

x = -10, y = 4294967286

如您所见,当我分配-by(long long) 时,它给出了错误的结果,但 x 的值符合预期。

阅读 asm 代码后,我发现当将负的 unsigned char 分配给 long long 时,编译器生成一条cdqe指令(见第 +25 行)将符号扩展为 rax,而当 unsigned int 为 long 时它不会做同样的事情长。

我知道我们得到这个值的原因4294967286是 rax 的高 32 位都为零,rax = 0x00000000fffffff6.

所以我的问题是为什么编译器cdqe在 unsigned int 情况下缺少指令?

Dump of assembler code for function main:
   0x000000000040052d <+0>:     push   rbp
   0x000000000040052e <+1>:     mov    rbp,rsp
   0x0000000000400531 <+4>:     sub    rsp,0x20
=> 0x0000000000400535 <+8>:     mov    BYTE PTR [rbp-0x1],0xa
   0x0000000000400539 <+12>:    mov    DWORD PTR [rbp-0x8],0xa
   0x0000000000400540 <+19>:    movzx  eax,BYTE PTR [rbp-0x1]
   0x0000000000400544 <+23>:    neg    eax
   0x0000000000400546 <+25>:    cdqe   
   0x0000000000400548 <+27>:    mov    QWORD PTR [rbp-0x10],rax
   0x000000000040054c <+31>:    mov    eax,DWORD PTR [rbp-0x8]
   0x000000000040054f <+34>:    neg    eax
   0x0000000000400551 <+36>:    mov    eax,eax
   0x0000000000400553 <+38>:    mov    QWORD PTR [rbp-0x18],rax
   0x0000000000400557 <+42>:    mov    rdx,QWORD PTR [rbp-0x18]
   0x000000000040055b <+46>:    mov    rax,QWORD PTR [rbp-0x10]
   0x000000000040055f <+50>:    mov    rsi,rax
   0x0000000000400562 <+53>:    mov    edi,0x400610
   0x0000000000400567 <+58>:    mov    eax,0x0
   0x000000000040056c <+63>:    call   0x400410 <printf@plt>
   0x0000000000400571 <+68>:    mov    eax,0x0
   0x0000000000400576 <+73>:    leave  
   0x0000000000400577 <+74>:    ret    

环境:

OS: CentOS Linux release 7.8.2003 (Core), Linux 3.10.0-327.el7.x86_64 #1 SMP Thu Nov 19 22:10:57 UTC 2015 x86_64 x86_64 GNU/Linux
Gcc: gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39)

回答

这与隐式整数转换有关。

  • unsigned char a:首先转换为int再否定。结果,-10

  • unsigned int b:是不是转换,因此-b否定了unsigned int,你会得到UINT_MAX - 10 + 1

如果您首先投射到目标类型-(long long)b,您也会到达-10那里。

进一步阅读:隐式转换


以上是将unsignedint(通过负数)分配给signedlonglong时的意外值的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>