比较有意思的两点:一,计算机补码表示;二,计算机如何区分无符号数和有符号数;
一:补码
1.补码的定义:
1.1.正数的补码是其本身;
1.2.负数的补码是符号位不变,其余位按位取反 ,再加1;
1.3.补码的补码还是自身;即对补码再做一次补码运算,得到原码。
2.计算机中存储数据是以补码的形式;
1 #include <stdio.h>
2
3 int main(int argc, char *argv[])
4 {
5 int i = -1;
6 char tmp1 = 0b01010101;//border to distinguish;
7 char j = -1;
8 char tmp2 = 0b10101010;//border to distinguish;
9
10 return 0;
11 }
利用gdb:x /8tb 0x************;//tmp2对应的地址;查看存在内存里的值;
(gdb) p &tmp2
$6 = 0x7fffffffe329 "\252\377U\377\377\377\377\001"
(gdb) x /8tb 0x7fffffffe329
0x7fffffffe329: 10101010 11111111 01010101 11111111 11111111 11111111 11111111 00000001
(gdb)
可以看到i在内存里是:0b11111111 11111111 11111111 11111111,占4个字节;(-1的补码);
j在内存里是:0b11111111 ,占1个字节;(-1的补码);
3.补码溢出
char a[i];
a[i] = -128;
a[i] -1 = 127;
-128是char型变量能表示的最小负数,再减去1,就会溢出,高位被丢弃;剩下的低八位,是7f;即127;这是补码提供一个巧合之处,这种循环的含义,很是神奇!!!
3.1补码这种被截断保持原有值的性质,也很神奇!!!
int i = -1;
char j = i;
变量j由于补码的性质截取了i的低八位,j的值依然为-1;
若是计算机采用原码存储:i在内存里是:0b10000000 00000000 00000000 00000001,占4字节;
j截断i的低八位,就变成了 0b00000001,占1字节;
j的值就变成了1;
那么考虑下面这个例子:
int m = -129;
char j = m;
这个截断之后,j变成了127;从循环意义上保持了原有的值;
二,无符号数和有符号数的区分:
清华大学,张悠慧老师,《汇编语言程序设计》
在硬件层面,不区分无符号数和有符号数;
编译器来区分无符号数和有符号数,通过条件码的cf, zf位;
图中w为数据位宽,例如图中w=4;
计算机如何区分无符号数和有符号数?
反汇编看一下区别:
#include <stdio.h>
#include <string.h>
int main()
{
int x = 2;
char * str = "abcd";
int y = (x - strlen(str) ) / 2;
printf("%d\n",y);
}