02 bits-ints-part1 数据的表示 | CSAPP

752 阅读7分钟

Overview

非数值数据的表示、数据的存储

  • 数据宽度单位

  • 硬件特征:大端/小端、对齐存放

数值数据的表示

  • 定点数的编码表示

  • 整数的表示 —— 无符号整数、带符号整数

  • 浮点数的表示

  • C语言程序的整数类型和浮点数类型

数据量的度量单位

存储二进制信息时的度量单位要比字节或字大得多

容量经常使用的单位有:

  • “千字节”(KB),1KB=210字节=1024B

  • “兆字节”(MB),1MB=220字节=1024KB

  • “千兆字节”(GB),1GB=230字节=1024MB

  • “兆兆字节”(TB),1TB=240字节=1024GB

通信中的带宽使用的单位有:

  • “千比特/秒”(kb/s),1kbps=103 b/s=1000 bps

  • “兆比特/秒”(Mb/s),1Mbps=106 b/s =1000 kbps

  • “千兆比特/秒”(Gb/s),1Gbps=109 b/s =1000 Mbps

  • “兆兆比特/秒”(Tb/s),1Tbps=1012 b/s =1000 Gbps

如果把b换成B,则表示字节而不是比特(位)

例如,10MBps表示 10兆字节/秒

数据的基本宽度

“字”和“字长”的概念不同

  • “字长”指数据通路的宽度。

数据通路指 CPU 内部数据流经的路径以及路径上的部件,主要是 CPU 内部进行数据运算、存储和传送的部件,这些部件的宽度基本上要一致,才能相互匹配。因此,”字长”等于 CPU 内部总线的宽度、运算器的位数、通用寄存器的宽度等

  • “字”表示被处理信息的单位,用来度量数据类型的宽度。

字和字长的宽度可以一样,也可不同。

例如,x86体系结构定义“字”的宽度为 16 位,但从 386 开始字长就是 32 位了。

Pasted image 20220928095428.png

数据的存储和排列顺序

80 年代开始,几乎所有机器都用字节编址

ISA设计时要考虑的两个问题:

  • 如何根据一个字节地址取到一个32位的字?- 字的存放问题

  • 一个字能否存放在任何字节边界?- 字的边界对齐问题

字节存放方式

大端方式(Big Endian):高有效位在前(低地址)

  • IBM 360/370

小端方式(Little Endian):低有效位在前(低地址)

  • Intel 80x86

机器中指令大小端区别只在于立即数。

字节交换问题

存放方式不同的机器间程序移植或数据通信时,会发生什么问题:

  • 每个系统内部是一致的,但在系统间通信时可能会发生问题!

  • 因为顺序不同,需要进行顺序转换

音、视频和图像(位图)等文件格式或处理程序都涉及到字节顺序问题:

  • Little endian: GIF, PC Paintbrush, Microsoft RTF,etc.

  • Big endian:  Adobe Photoshop, JPEG, MacPaint, etc

矢量图不会出现这种问题,因为每个像素是计算出来的(映射)

对齐 Alignment

Alignment: 要求数据的地址是相应的边界地址

  • 目前机器字长一般为 32 位或 64 位,而存储器地址按字节编址

  • 指令系统支持对字节、半字、字及双字的运算,也有位处理指令

  • 各种不同长度的数据存放时,有两种处理方式:

    • 按边界对齐 (假定存储字的宽度为32位,按字节编址)

      • 字地址:4的倍数(低两位为0)
      • 半字地址:2的倍数(低位为0)
      • 字节地址:任意
    • 不按边界对齐

      • 坏处:可能会增加访存次数!
      • (学了存储器组织后会更明白!)

例如 int i, short k, double x, char c, short j, ...

存储器按字节编址

Pasted image 20220928104612.png

按边界对齐每次只能读写某个字地址开始的4个单元中连续的 1 个、2 个、3 个或 4 个字节

Pasted image 20220928104628.png

边界不对齐虽节省了空间,但增加了访存次数!

需要权衡,目前来看,浪费一点存储空间没有关系!

对齐举例

Pasted image 20220928105440.png

逻辑数据的编码表示

表示

  • 用一位表示 。例如,真:1  /  假:0

  • N 位二进制数可表示 N 个逻辑数据,或一个位串

运算

  • 按位进行

  • 如:按位与 / 按位或 / 逻辑左移 / 逻辑右移 等   

识别

  • 逻辑数据和数值数据在形式上并无差别,也是一串 0/1 序列,机器靠指令来识别。

位串

  • 用来表示若干个状态位或控制位(OS中使用较多)

  • 例如,x86的标志寄存器含义如下:

x86汇编之——8086寄存器讲解 - 知乎

C 语言位运算符:

  • 按位与 &
  • 按位或 |
  • 按位异或 ^
  • 按位取反 ~

C 语言位移操作:

  • 左移(Left Shift):<< 后面补零(每移一位乘以 2)
  • 右移(Right Shift):>>
    • 逻辑右移:前面补零(单纯的移位操作)
    • 算数右移:前面补符号位( 每移一位除以 2)

注意:如果移动的位数 k 大于机器的数据类型的长度 w ,实际位移量为 k mod w

字符的编码表示

西文字符

特点

  • 是一种拼音文字,用有限几个字母可拼写出所有单词

  • 只对有限个字母和数学符号、标点符号等辅助字符编码

  • 所有字符总数不超过256个,使用7或8个二进位可表示

表示(常用编码为7位ASCII码)

  • 十进制数字:0/1/2…/9(30H)

  • 英文字母:A/B/…/Z/a/b/…/z(41H、61H)

  • 专用符号:+/-/%/*/&/……

  • 控制字符(不可打印或显示)(回车:0DH;换行:0AH)

操作

  • 字符串操作,如:传送/比较 等

汉字及国际字符

特点

  • 汉字是表意文字,一个字就是一个方块图形。

  • 汉字数量巨大,总数超过6万字,给汉字在计算机内部的表示、汉字的传输与交换、汉字的输入和输出等带来了一系列问题。

编码形式

  • 有以下几种汉字代码:

    • 输入码:对汉字用相应按键进行编码表示,用于输入
    • 内码:用于在系统中进行存储、查找、传送等处理 - 字模点阵或轮廓描述:描述汉字字模点阵或轮廓,用于显示/打印

补码、无符号数

深入理解计算机系统00 - 无符号整数、二进制补码_哔哩哔哩_bilibili

补码

定义:第一位是符号位,权重加负号,其余权重就是二进制码

B2Tw(x)=xw12w1+i=0w2xi2iB2T_{w}(\vec{x})=-x_{w-1}2^{w-1}+\sum\limits_{i=0}^{w-2}x_{i}2^{i}

正数的补码是它本身,负数的补码由其绝对值按位取反再加一

事实上,对于补码编码的整数,对其取负的操作就是在他的底层位表示上按位取反加一。

x = 1
-x = -1
// x = 0000 0000 0000 0000 0000 0000 0000 0001 = 1
// ~x = 1111 1111 1111 1111 1111 1111 1111 1110
// ~x + 1 = 1111 1111 1111 1111 1111 1111 1111 1111 = -1
x = -2147483647-1
// x = 1000 0000 0000 0000 0000 0000 0000 0000 = -2147483648
// ~x = 0111 1111 1111 1111 1111 1111 1111 1111
// ~x + 1 = 1000 0000 0000 0000 0000 0000 0000 = -2147483648
-x = -2147483648

无符号数

定义:权重就是二进制码

B2Uw(x)=i=0w1xi2iB2U_{w}(\vec{x})=\sum\limits_{i=0}^{w-1}x_{i}2^{i}

相同位表示的 ww 位编码,有符号数表示的正数与无符号数一样,编码表示的有符号数的负数真实值加 2w2^{w} 是编码表示的无符号数的真实值。

整型扩展

无符号数:直接在前面补零

有符号数:在前面补符号位

整型截断

无符号数:截断至 kk 位,原数值 modxk\mod x^{k}

有符号数:先转为无符号数,再根据无符号数截断方法计算阶段后的无符号数值,再转回有符号数。