2.数据的表示
2.1
2.1.1 10进制和2进制
转换的概念在数据表示里的反映,高级语言写的程序,而指令只能指定数据放在某个寄存器里,或者放在存储器里。
2.1.2
数据在计算机里的表示。
首先要会进制转换。整数比较容易,小数会有个问题,有些小数无法精确用二进制表示。
此外还有小数点的约定,小数点约定在固定位置为定点书,小数点位置可变,就是浮点数。
定点小小数用来表示浮点数的尾数部分。
定点整数用来表示整数,分带符号数和无符号数。
任何实数都可以表示为:
其中s用来确定符号,M是二进制定点小数,称为X的尾数,E为定点整数。因此任何一个小数都可以用两个定点整数来表示。
到这里,又要研究定点整数来怎么表示了。
2.2
数据表示的三要素
进位计数制
定、浮点表示
如何用二进制编码
不同计数制之间的转换
定、浮点数表示(解决小数点的问题)
定点整数,定点小数
浮点数(一个定点小数和一个定点整数来表示)
接下来问题到了如何表示一个定点数的问题,即定点数的编码
2.2.1
编码有原码、反码、补码
原码只是用最高位来表示符号,人容易理解,但是有问题
0表示不唯一
加减运算不统一
要额外处理符号位
还有移码,很简单,将每个数值加上一个偏置常数。移码表示浮点数的阶
2.2.2 补码和模运算
一个模运算系统,一个数和对模取余等价。
指针表是模12系统,(10+8)%12=6=10-4
也即在模12的系统里-4=8
一个负数的补码等于模减负数的绝对值
使用补码可以实现加和减的统一。
计算机内数据保存都是补码形式,通过真值算补码:补码=真值+模值
2.2.3 补码和真值的对应关系
假定机器数有n位,
补码=模值+真值
对于正数来说,就是本身。对于负数,数值部分按位取反再加一。
那么给出补码如何求真值,有公式,当然按照上面倒着来更容易。
2.3
有了编码基础的知识,下面来看C语言里整数在机器里的存储方式
整数有char short int / long int / long long int
类型可以声明为singed / unsigned
指针本质也是个整数
2.3.1 整数
整数在机器里以比特流的形式保存,描述比特位的时候,用最左位或最右位来描述有歧义(有的机器最高有效位在左,有的机器在右)。
因此用最高有效位MSB,最低有效位LSB来描述。
无符号数很容易。
带符号数,机器里用MSB来表示符号。
有三种定点编码方式
原码,定点小数,表示浮点数尾数
移码,定点整数,表示浮点数的阶(指数)
补码,用来表示带符号整数
用补码的优势在前面又说,可以使得加减法统一起来。
关于不同标准下对于特殊数据出现的bug,参考教材。
2.3.1 浮点数
浮点数的类型float(32bit),double(64bit),还有long double
科学计数法可以把任何一个十进制的数写成指数形式,规格化的是小数点前就一位整数。当然并不唯一。
表示方法
2.3.2 ieee 754
IEEE 754标准
早期,不同机器自己约定自己的,导致一台机器上的程序换到另一台机器会出问题,知道80年代初都是这个样子。1985年才有了754标准,现在通用计算机都使用这个标准。
对于单精度
阶码8bit,可表示-126~127,使用移码表示,码值为1~254,偏移值127,全0全1有特殊含义。
双精度浮点数,阶码11bit,尾数52bit,阶码偏移值1023
所以一个机器码转化为真值:
举例子,一个float类型的变量,内存里的值为BEE00000H,真值为
此外还有一些特殊情况,
全零指数和全零尾数表示零,正负零。
此外还可以表示正负无穷大,浮点数除以0不会像整数一样有异常,而是用无穷。
无穷用全1阶码,全零尾数来表示。
此外还有“不是一个数“的表示NaN,全1阶码,尾数非零。这种情况会在负数开根号等情况出现,可以辅助调试程序
此外还有全零阶码的情况,表示非规格化数。
最小的规格化数为, 在这个数到0之间,可以表示非规格化的数。
此外浮点可以表示的数是有限的,因此存在精度问题
2.5 非数值数据
逻辑关系的真假,逻辑量一个bit就可以表示了,N位二进制数可以表示N个逻辑数据。
逻辑数据和数值数据在形式上没有区别,都是01序列,在运算时靠指令来区别。操作码是ADD,那就是数值数据。
计算机也可以处理字符,西文字符用有限字母就可以拼写所有单词,因此只需要处理有限个字符。常用的就是ascii码。
对字符串的操作有传送、比较等。
ascii用7个bit编码,要特别熟悉的编码,空格,换行,回车。
汉字的表示就比较复杂了,一个字是一个方块图形,这就带来了表示和存储的问题。
汉字编码形式有输入码,如输入法拼音,五笔。还有内码,用于在系统里进行存储、查找、传送等处理。还有字模点阵或轮廓描述,用于显示。
西文字符没有输入码,键盘直接输进去就是,西文字符的内码就是ascii码,也有点阵描述。
比较早的汉字编码为GB2312,这个国标有三部分,字母数字符号英文俄文罗马字母拼音等不是汉字的字符;一级常用汉字3755个,按照汉语拼音排列;二级常用汉字3008个。
汉字有区位码,码表94行94列,行号为区号,列号为位号,各占7位。用14位就可以指出汉字在码表中的位置。
每个汉字的区号和位号各自加上32(20H)就得到了国标码。显然汉字内码需要2个字节。为了与ascii码区别,把最高位置1。
此外还有多媒体信息,图形图像音频视频等信息。图形用构建图形的直线曲线左边点控制点等来描述;图像用像素点的数值数据来表示;音频通过采样量化获得;视频信息描述随时间变化的图像;音乐信息MIDI记录乐器的演奏编码信息。
2.6 数据的宽度和存储容量
bit是计算机里的最小单位
信息的基本计量单位Byte
现代计算机,存储器按字节编址
字节是最小可寻址单位
LSB表示最低有效字节
此外还有“字”的概念,IA32中字是16位,这也是从8086延续下来的。
DWORD 32bit
QWORD 64bit
字长是定点数据通路的宽度,即计算机内部总线的宽度,或者ALU运算的宽度,寄存器的宽度,都是一样的。字和字长没啥关系,
x86结构字16bit,字长32bit;MIPS结构字32bit,字长32bit
数据量的度量单位KB、MB、GB、TB
通信里的带宽的单位kb/s、Mb/s、Gb/s、bps,区别Byte和bit
高级语言的不同数据类型,在不同机器上实现出来的长度可能不同。
2.7 数据存储时的字节排列
存储器编制方式,大端和小端。
80年代开始,所以通用计算机都是按字节编址。因此一个数据可能占据多个存储单元,如double要占用4个byte
int也要存放4个Byte,那么存放这个数的地址指的是最大地址还是最小地址呢,一般来说,是最小地址。看有个问题,最小地址放最低字节,也可以反过来。
存放方式关系到取数指令是否可以正确的取出数据。
高址高位,小端;高址地位,大端。
MIPS架构:高址高位,小端人看着费劲,但是强制类型转换直接截断就行
8086:高址地位,大端人看着比较容易
判断大小端可以通过C语言特性写个程序执行来
输出0x12是小端,输出0x78是大端。
还有这种语法也可以实现
同样通过b的值来判断大小端。
再个举例子,假设小端机器,一条指令的地址为1000,这条指令的汇编形式为mov ax,0x12345
mov的操作码为40H,寄存器ax编号1,bx编号2,立即数32位,那么存放顺序
(1000)40 12 45 23 01 00 (1005)
在大端机器里的存放方式
(1000)40 12 00 01 23 45(1005)
同样的,看一个反汇编的例子,由反汇编器生成的IA32机器器
80483d2: 89 85 a0 fe ff ff mov %eax, 0xfffffea0(%ebp)
这条指令占了6个Byte。
那么可以看出立即数如果是有符号数的话真值为(懒得算了),存放地址的d4,
intel处理器小端方式,高址高位,不方便人看,方便机器使用。
有的机器是大端,有的机器是小端,这就有了字节交换的问题,虽然每台机器上都是一样的,但是程序在机器之间移植或数据通信时会出问题。
音频视频图像等文件的处理都涉及到字节顺序的问题。
小端:gif、
大端:Photoshop、jpeg
最后更新于