将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
如您所见,当我分配-b给y(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 chara:首先转换为int再否定。结果,-10。 -
本
unsigned intb:是不是转换,因此-b否定了unsigned int,你会得到UINT_MAX - 10 + 1。
如果您首先投射到目标类型-(long long)b,您也会到达-10那里。
进一步阅读:隐式转换
THE END
二维码