- 整数的编码-真值和机器数
带符号整数按照补码进行真值表示;无符号整数按照原码进行真值表示。
举个例子:
#include <iostream>
#include <stdio.h>
int main()
{
int ai = 100;
int bi = 2147483648;
int ci = -100;
unsigned au = 100;
unsigned bu = 2147483648;
unsigned cu = -100;
printf("ai=%d, bi=%d, ci=%d\n",ai, bi, ci);
printf("au=%u, bu=%u, cu=%u\n",ai, bi, ci);
return 0;
}
运行结果为:
ai=100, bi=-2147483648, ci=-100
au=100, bu=2147483648, cu=4294967196
反汇编后:
int main()
{
400706: 55 push %rbp
400707: 48 89 e5 mov %rsp,%rbp
40070a: 48 83 ec 20 sub $0x20,%rsp
int ai = 100;
40070e: c7 45 e8 64 00 00 00 movl $0x64,-0x18(%rbp)
int bi = 2147483648;
400715: c7 45 ec 00 00 00 80 movl $0x80000000,-0x14(%rbp)
int ci = -100;
40071c: c7 45 f0 9c ff ff ff movl $0xffffff9c,-0x10(%rbp)
unsigned au = 100;
400723: c7 45 f4 64 00 00 00 movl $0x64,-0xc(%rbp)
unsigned bu = 2147483648;
40072a: c7 45 f8 00 00 00 80 movl $0x80000000,-0x8(%rbp)
unsigned cu = -100;
400731: c7 45 fc 9c ff ff ff movl $0xffffff9c,-0x4(%rbp)
printf("ai=%d, bi=%d, ci=%d\n",ai, bi, ci);
400738: 8b 4d f0 mov -0x10(%rbp),%ecx
40073b: 8b 55 ec mov -0x14(%rbp),%edx
40073e: 8b 45 e8 mov -0x18(%rbp),%eax
400741: 89 c6 mov %eax,%esi
400743: bf 54 08 40 00 mov $0x400854,%edi
400748: b8 00 00 00 00 mov $0x0,%eax
40074d: e8 5e fe ff ff callq 4005b0 <printf@plt>
printf("au=%u, bu=%u, cu=%u\n",ai, bi, ci);
400752: 8b 4d f0 mov -0x10(%rbp),%ecx
400755: 8b 55 ec mov -0x14(%rbp),%edx
400758: 8b 45 e8 mov -0x18(%rbp),%eax
40075b: 89 c6 mov %eax,%esi
40075d: bf 69 08 40 00 mov $0x400869,%edi
400762: b8 00 00 00 00 mov $0x0,%eax
400767: e8 44 fe ff ff callq 4005b0 <printf@plt>
return 0;
40076c: b8 00 00 00 00 mov $0x0,%eax
}
2 浮点数的编码-真值和机器数
浮点数使用IEEE 754标准进行编码
#include <iostream>
#include <stdio.h>
int main()
{
int ai = 100;
int bi = -100;
float af = 100;
float bf = -100;
printf("ai=%d, bi=%d\n",ai, bi);
printf("af=%f, bf=%f\n",af, bf);
return 0;
}
反汇编后结果为:
int main()
{
400706: 55 push %rbp
400707: 48 89 e5 mov %rsp,%rbp
40070a: 48 83 ec 10 sub $0x10,%rsp
int ai = 100;
40070e: c7 45 f0 64 00 00 00 movl $0x64,-0x10(%rbp)
int bi = -100;
400715: c7 45 f4 9c ff ff ff movl $0xffffff9c,-0xc(%rbp)
float af = 100;
40071c: f3 0f 10 05 3c 01 00 movss 0x13c(%rip),%xmm0 # 400860 <_IO_stdin_used+0x20>
400723: 00
400724: f3 0f 11 45 f8 movss %xmm0,-0x8(%rbp)
float bf = -100;
400729: f3 0f 10 05 33 01 00 movss 0x133(%rip),%xmm0 # 400864 <_IO_stdin_used+0x24>
400730: 00
400731: f3 0f 11 45 fc movss %xmm0,-0x4(%rbp)
printf("ai=%d, bi=%d\n",ai, bi);
400736: 8b 55 f4 mov -0xc(%rbp),%edx
400739: 8b 45 f0 mov -0x10(%rbp),%eax
40073c: 89 c6 mov %eax,%esi
40073e: bf 44 08 40 00 mov $0x400844,%edi
400743: b8 00 00 00 00 mov $0x0,%eax
400748: e8 63 fe ff ff callq 4005b0 <printf@plt>
printf("af=%f, bf=%f\n",af, bf);
40074d: f3 0f 5a 4d fc cvtss2sd -0x4(%rbp),%xmm1
400752: f3 0f 5a 45 f8 cvtss2sd -0x8(%rbp),%xmm0
400757: bf 52 08 40 00 mov $0x400852,%edi
40075c: b8 02 00 00 00 mov $0x2,%eax
400761: e8 4a fe ff ff callq 4005b0 <printf@plt>
return 0;
400766: b8 00 00 00 00 mov $0x0,%eax
}
这里面获取浮点数用到了movss指令,具体可以看这个帖子:
SSE指令集
使用gdb来看看机器数
(gdb) b main
Breakpoint 1 at 0x40070e: file float.cpp, line 6.
(gdb) r
Starting program: /home/aitian/myProject/OS/day3/float
Breakpoint 1, main () at float.cpp:6
6 int ai = 100;
(gdb) i r rip
rip 0x40070e 0x40070e <main()+8>
(gdb) s
7 int bi = -100;
(gdb) s
8 float af = 100;
(gdb) s
9 float bf = -100;
(gdb) s
11 printf("ai=%d, bi=%d\n",ai, bi);
(gdb) i r rip
rip 0x400736 0x400736 <main()+48>
(gdb) i r rsp rbp
rsp 0x7fffffffd7a0 0x7fffffffd7a0
rbp 0x7fffffffd7b0 0x7fffffffd7b0
(gdb) x/4xw $rsp
0x7fffffffd7a0: 0x00000064 0xffffff9c 0x42c80000 0xc2c80000
可以看出ai,bi这两个整数对应的机器数是0x00000064 0xffffff9c
af,bf这两个浮点数对应的机器数是0x42c80000 0xc2c80000
3 数据存储排列方式和对齐方式
不同的类型占用的宽度是不一样的。
数据的排列方式就是大端小端.
比如我的机器就是小端的:
(gdb) i r rsp rbp
rsp 0x7fffffffd7a0 0x7fffffffd7a0
rbp 0x7fffffffd7b0 0x7fffffffd7b0
(gdb) x/16xb $rsp
0x7fffffffd7a0: 0x90 0xd8 0xff 0xff 0xff 0x64 0x64 0x00
0x7fffffffd7a8: 0x64 0x00 0x00 0x00 0x78 0x56 0x34 0x12
数据的对齐方式
3 整数类型之间的转换
第一种情况:宽度相同
第二种情况:短的给长的
第三种情况:长的给短的
4 整数和浮点数的转换
整数和浮点数的转换是在编码格式上的转换,而不是机器数上的直接复制。
举个例子:
#include <stdio.h>
int main()
{
int i1 = 0x7fffffff;
int i2;
int itemp;
float f1=0x987654321;
float f2;
float ftemp;
ftemp = i1;
i2 = ftemp;
itemp = f1;
f2 = itemp;
printf("i1=%d,i2=%d\n,f1=%f,f2=%f\n", i1,i2,f1,f2);
return 0;
}
运行后结果为:
i1=2147483647,i2=-2147483648
,f1=40926265344.000000,f2=-2147483648.000000
分析一下原因:
对应第一个转换
对应第二个转换
5.整数加减运算
由于补码的作用,整数减法也是按照加法计算的。整数加减注意溢出。
怎么判断整数加减是否有溢出存在呢:
对于无符号运算:
而对于带符号整数的加减运算:
6.浮点数运算
浮点数的真值与机器数的互相转化:
举个例子如下:
#include <stdio.h>
int main()
{
// 无穷大
float f1 = 4e38;
float f2 = 5e38;
float f3 = 6e38;
// 负无穷大
float f4 = -4e38;
float f5 = -5e38;
float f6 = -6e38;
// 0, -0
float f7 = 0;
float f8 = -f7;
// 规格化数
float f9 = 5.0;
float f10 = 0.1;
float f11 = -5;
float f12 = -0.1;
// 非规格化数
float f13 = 1e-40;
float f14 = -1e-40;
// 无定义数
float f15 = f1 + f4;
float f16 = -f15;
// 除以0,无穷大
float f17 = f9/f7;
return 0;
}
反汇编后:
int main()
{
4004d6: 55 push %rbp
4004d7: 48 89 e5 mov %rsp,%rbp
// 无穷大
float f1 = 4e38;
4004da: f3 0f 10 05 7e 01 00 movss 0x17e(%rip),%xmm0 # 400660 <_IO_stdin_used+0x10>
4004e1: 00
4004e2: f3 0f 11 45 bc movss %xmm0,-0x44(%rbp)
float f2 = 5e38;
4004e7: f3 0f 10 05 71 01 00 movss 0x171(%rip),%xmm0 # 400660 <_IO_stdin_used+0x10>
4004ee: 00
4004ef: f3 0f 11 45 c0 movss %xmm0,-0x40(%rbp)
float f3 = 6e38;
4004f4: f3 0f 10 05 64 01 00 movss 0x164(%rip),%xmm0 # 400660 <_IO_stdin_used+0x10>
4004fb: 00
4004fc: f3 0f 11 45 c4 movss %xmm0,-0x3c(%rbp)
// 负无穷大
float f4 = -4e38;
400501: f3 0f 10 05 5b 01 00 movss 0x15b(%rip),%xmm0 # 400664 <_IO_stdin_used+0x14>
400508: 00
400509: f3 0f 11 45 c8 movss %xmm0,-0x38(%rbp)
float f5 = -5e38;
40050e: f3 0f 10 05 4e 01 00 movss 0x14e(%rip),%xmm0 # 400664 <_IO_stdin_used+0x14>
400515: 00
400516: f3 0f 11 45 cc movss %xmm0,-0x34(%rbp)
float f6 = -6e38;
40051b: f3 0f 10 05 41 01 00 movss 0x141(%rip),%xmm0 # 400664 <_IO_stdin_used+0x14>
400522: 00
400523: f3 0f 11 45 d0 movss %xmm0,-0x30(%rbp)
// 0, -0
float f7 = 0;
400528: 66 0f ef c0 pxor %xmm0,%xmm0
40052c: f3 0f 11 45 d4 movss %xmm0,-0x2c(%rbp)
float f8 = -f7;
400531: f3 0f 10 4d d4 movss -0x2c(%rbp),%xmm1
400536: f3 0f 10 05 32 01 00 movss 0x132(%rip),%xmm0 # 400670 <_IO_stdin_used+0x20>
40053d: 00
40053e: 0f 57 c1 xorps %xmm1,%xmm0
400541: f3 0f 11 45 d8 movss %xmm0,-0x28(%rbp)
// 规格化数
float f9 = 5.0;
400546: f3 0f 10 05 32 01 00 movss 0x132(%rip),%xmm0 # 400680 <_IO_stdin_used+0x30>
40054d: 00
40054e: f3 0f 11 45 dc movss %xmm0,-0x24(%rbp)
float f10 = 0.1;
400553: f3 0f 10 05 29 01 00 movss 0x129(%rip),%xmm0 # 400684 <_IO_stdin_used+0x34>
40055a: 00
40055b: f3 0f 11 45 e0 movss %xmm0,-0x20(%rbp)
float f11 = -5;
400560: f3 0f 10 05 20 01 00 movss 0x120(%rip),%xmm0 # 400688 <_IO_stdin_used+0x38>
400567: 00
400568: f3 0f 11 45 e4 movss %xmm0,-0x1c(%rbp)
float f12 = -0.1;
40056d: f3 0f 10 05 17 01 00 movss 0x117(%rip),%xmm0 # 40068c <_IO_stdin_used+0x3c>
400574: 00
400575: f3 0f 11 45 e8 movss %xmm0,-0x18(%rbp)
// 非规格化数
float f13 = 1e-40;
40057a: f3 0f 10 05 0e 01 00 movss 0x10e(%rip),%xmm0 # 400690 <_IO_stdin_used+0x40>
400581: 00
400582: f3 0f 11 45 ec movss %xmm0,-0x14(%rbp)
float f14 = -1e-40;
400587: f3 0f 10 05 05 01 00 movss 0x105(%rip),%xmm0 # 400694 <_IO_stdin_used+0x44>
40058e: 00
40058f: f3 0f 11 45 f0 movss %xmm0,-0x10(%rbp)
40058f: f3 0f 11 45 f0 movss %xmm0,-0x10(%rbp)
// 无定义数
float f15 = f1 + f4;
400594: f3 0f 10 45 bc movss -0x44(%rbp),%xmm0
400599: f3 0f 58 45 c8 addss -0x38(%rbp),%xmm0
40059e: f3 0f 11 45 f4 movss %xmm0,-0xc(%rbp)
float f16 = -f15;
4005a3: f3 0f 10 4d f4 movss -0xc(%rbp),%xmm1
4005a8: f3 0f 10 05 c0 00 00 movss 0xc0(%rip),%xmm0 # 400670 <_IO_stdin_used+0x20>
4005af: 00
4005b0: 0f 57 c1 xorps %xmm1,%xmm0
4005b3: f3 0f 11 45 f8 movss %xmm0,-0x8(%rbp)
// 除以0,无穷大
float f17 = f9/f7;
4005b8: f3 0f 10 45 dc movss -0x24(%rbp),%xmm0
4005bd: f3 0f 5e 45 d4 divss -0x2c(%rbp),%xmm0
先看看f1,f2,f3这三个无穷大:
(gdb) x/3xw $rbp-0x3c
0x7fffffffd774: 0x7f800000 0xff800000 0xff800000
看看f4,f5,f6这三个负无穷大:
(gdb) x/3xw $rbp-0x30
0x7fffffffd780: 0xff800000 0x00000000 0x80000000
再看正零和负零:
(gdb) x/2xw $rbp-0x2c
0x7fffffffd784: 0x00000000 0x80000000
其他的就不一一看了。反正和前面的规范是能对上的。