c - 将无符号整数(通过否定它)分配给有符号长长时的意外值
问题描述
我碰巧遇到了一个奇怪的问题,请参见下面的代码:
#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 = %lld\n", x, y);
return 0;
}
输出:
x = -10, y = 4294967286
如您所见,当我分配-b
给y
(long long) 时,它给出了错误的结果,但 x 的值符合预期。
在阅读了asm代码后,我发现当将负无符号字符分配给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
首先转换为 anint
然后取反。结果,-10
。:没有
unsigned int
b
被转换,所以否定了你会得到.-b
unsigned int
UINT_MAX - 10 + 1
如果您先转换为目标类型-(long long)b
,您也会到达-10
那里。
进一步阅读:隐式转换
推荐阅读
- html - 如何直观地对单选按钮进行分组?
- python - 遍历嵌套数组并查找索引号
- reactjs - 使用条件然后映射反应问题
- ios - 复制文件时文件管理器“文件存在”
- excel - 如何自动过滤然后仅复制和粘贴可见单元格
- angularjs - 加载服务数据并在 fullCalendar 中显示使用 AngularJS 和 FullCalendar
- java - 为什么这个测试 junit 测试返回 400?
- python - Python 和 Tweepy:CSV 文件中的结果
- android - 在运行时将文本视图添加到 relativlayout
- swift - 从文本字段输入在现有表中创建新行。SwiftUI(故事板)