32位有符号整型数值范围是[-2147484648, 2147484647]。数据溢出,数据存储会以补码的形式存储。因此最高位变成了1,成为了一个复数。建议改为unsigned int,输出格式为%u就可显示正常
32位有符号整型数值范围是[-2147484648, 2147484647],a/-1结果应该是2147484648,但是2147484648超出了32位有符号整型的数值范围,属于溢出。C/C++语言标准里把有符号整型溢出划为未定义行为,其结果依赖编译器实现。
From https://en.cppreference.com/w/c/language/operator_arithmetic#Overflows
When signed integer arithmetic operation overflows (the result does not fit in the result type), the behavior is undefined: it may wrap around according to the rules of the representation (typically 2's complement), it may trap on some platforms or due to compiler options (e.g. -ftrapv in GCC and Clang), or may be completely optimized out by the compiler.
下面只给出gcc编译器对这种溢出的结果解释
源码
#include <stdio.h>
int main()
{
int a = 0x80000000;
int b = a / -1;
printf("%d\n", b);
}
汇编代码
.file "main.c"
.text
.section .rodata
.LC0:
.string "%d\n"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl $-2147483648, -4(%rbp) // a = 0x80000000
movl -4(%rbp), %eax
negl %eax // 计算a/-1
movl %eax, -8(%rbp) // 结果赋给b
movl -8(%rbp), %eax
movl %eax, %esi
leaq .LC0(%rip), %rdi
movl $0, %eax
call printf@PLT
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Debian 10.2.1-6) 10.2.1 20210110"
.section .note.GNU-stack,"",@progbits
由上面代码可以看出a/-1是由negl指令完成计算的
negl指令相当于取反加一 (https://www.aldeid.com/wiki/X86-assembly/Instructions/neg)
对0x80000000取反加一结果还是0x80000000
not(0x80000000) => 0x7FFFFFFF
not(0x80000000) + 1 => 0x80000000
整型最高位是符号位,所以最终输出结果是-2147483648