# 数据的表示

## 2.1

### 2.1.1 10进制和2进制

转换的概念在数据表示里的反映，高级语言写的程序，而指令只能指定数据放在某个寄存器里，或者放在存储器里。

### 2.1.2

数据在计算机里的表示。

首先要会进制转换。整数比较容易，小数会有个问题，有些小数无法精确用二进制表示。

此外还有小数点的约定，小数点约定在固定位置为定点书，小数点位置可变，就是浮点数。

定点小小数用来表示浮点数的尾数部分。

定点整数用来表示整数，分带符号数和无符号数。

任何实数都可以表示为：$$X = (-1)^s \times M \times R^E$$

其中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

所以一个机器码转化为真值：

$$sp = (-1)^s \times (1+尾数) \times 2^{阶码-127}$$

举例子，一个float类型的变量，内存里的值为BEE00000H，真值为

此外还有一些特殊情况，

全零指数和全零尾数表示零，正负零。

此外还可以表示正负无穷大，浮点数除以0不会像整数一样有异常，而是用无穷。

无穷用全1阶码，全零尾数来表示。

此外还有“不是一个数“的表示NaN，全1阶码，尾数非零。这种情况会在负数开根号等情况出现，可以辅助调试程序

此外还有全零阶码的情况，表示非规格化数。

最小的规格化数为$$2^{-126}$$， 在这个数到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语言特性写个程序执行来

```c
#include <stdio.h>

void main()
{
  union NUM
  {
    int a;
    char b;
  } num;
  num.a = 0x12345678;
  printf("%x",num.b);
}

```

输出0x12是小端，输出0x78是大端。

还有这种语法也可以实现

```c
int a = 0x12345678;
char b;
b = *(char *)&a
```

同样通过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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://embedded.xym.work/1_2_csapp/2-shu-ju-de-biao-shi.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
