目录
1 数据单位
- 位(bit)
- 定义:位是计算机中最小的数据单位,也是信息量的最小单位。它只能表示0或1两种状态,是二进制数据的基础。
- 应用:在数字电路和计算机技术中,位是构成所有数字和信息的基础。
- 字节(Byte)
- 定义:字节是计算机中常用的数据单位,由8个位(bit)组成。它是信息组织和存储的基本单位,也是计算机体系结构的基本单位。
- 应用:在计算机中,一个字节通常用于表示一个字符(如英文字母)的编码,而汉字等复杂字符通常需要多个字节来表示。
- 换算:1 Byte = 8 bits
- 千字节(KB, KiloByte)
- 定义:千字节是更大的存储单位,由1024个字节组成(在计算机科学中,KB的“千”实际上是按照1024【2的10次方】来计算的,而不是1000)。
- 应用:KB常用于表示较小的文件或数据块的大小。
- 换算:1 KB = 1024 Bytes
- 兆字节(MB, MegaByte)
- 定义:兆字节是更大的存储单位,由1024个千字节组成。
- 应用:MB常用于表示中等大小的文件或程序的存储需求。
- 换算:1 MB = 1024 KB = 1024 × 1024 Bytes = 1,048,576 Bytes
- 吉字节(GB, GigaByte)
- 定义:吉字节是更大的存储单位,由1024个兆字节组成。
- 应用:GB常用于表示大型文件、数据库或操作系统的存储需求。
- 换算:1 GB = 1024 MB = 1024 × 1024 × 1024 Bytes = 1,073,741,824 Bytes
- 太字节(TB, TeraByte)
- 定义:太字节是更大的存储单位,由1024个吉字节组成。
- 应用:TB常用于表示大型数据中心、企业存储解决方案或云存储的容量。
- 换算:1 TB = 1024 GB
- 拍字节(PB, PetaByte)
- 定义:拍字节是更大的存储单位,由1024个太字节组成。
- 应用:PB级存储通常用于处理大规模数据集,如科学研究、天气预报等领域。
- 换算:1 PB = 1024 TB
其他单位:
更大的单位还有艾字节(EB, ExaByte)、泽字节(ZB, ZettaByte)、尧字节(YB, YottaByte)等,它们之间的换算关系也是基于1024的幂次方。
2 数据进制
计算机中只能存储和识别二进制数,即0和1,对应物理硬件上则是低(0)、高(1)电平。为了更方便地观察内存中的二进制数情况,除我们正常使用的十进制数外,计算机还提供了十六进制数和八进制数,十进制、八进制、十六进制是为了人类使用而设计的。
进制 | 组成 | 基数 | 运算法则 | 前缀 | 示例 |
---|---|---|---|---|---|
二进制 | 0, 1 | 2 | 加法:逢二进一; 减法:借一当二; 乘法:同十进制,但每位积不超过1; 除法:同十进制,但余数只能为0或1 |
0b 或 0B 作为前缀或无(视上下文而定) | 0b1010 (等价于十进制的10) 或 1010 |
八进制 | 0-7 | 8 | 加法:逢八进一; 减法:借一当八; 乘法:同十进制,但每位积不超过7; 除法:同十进制,但余数只能为0-7 |
0(数字零)作为前缀 | 012 表示八进制的 12,它等价于十进制的 10 |
十进制 | 0-9 | 10 | 加法:逢十进一; 减法:借一当十; 乘法:直接相乘,注意进位; 除法:直接相除,注意余数 |
无特定前缀 | 123 (就是常规的十进制数) |
十六进制 | 0-9, A-F (a-f 也可,大小写不敏感) | 16 | 加法:逢十六进一,A-F 表示 10-15; 减法:借一当十六; 乘法:同十进制,但每位积不超过F; 除法:同十进制,但余数只能为0-F |
0x 或 0X(x 可以是大写或小写)作为前缀 | 0xA3 或 0xa3 表示十六进制的 A3,它等价于十进制的 163 |
C语言本身不支持直接以二进制字面量的形式赋值给整数(即没有直接的二进制前缀),但我们可以使用十进制、八进制(以数字0开头)、十六进制(以0x或0X开头)来赋值,如下代码所示:
#include <stdio.h>
int main() {
int decimalVar = 123; // 十进制赋值
int octalVar = 0173; // 八进制赋值(在C中,这实际上是十进制中的123)
int hexVar = 0x7b; // 十六进制赋值(在C中,这同样是十进制中的123)
int hexVarUpper = 0X7B; // 十六进制赋值(大写,与0x7b相同)
// 打印decimalVar的十进制、八进制、十六进制(小写和大写)
printf("decimalVar的十进制:%d\n", decimalVar); //123
printf("decimalVar的八进制:%#o\n", decimalVar); //0173
printf("decimalVar的十六进制(小写):%#x\n", decimalVar); //0x7b
printf("decimalVar的十六进制(大写):%#X\n", decimalVar); //0x7B
// 打印octalVar的十进制、八进制、十六进制(小写和大写)
printf("octalVar的十进制:%d\n", octalVar); //123
printf("octalVar的八进制:%#o\n", octalVar); //0173
printf("octalVar的十六进制(小写):%#x\n", octalVar); //0x7b
printf("octalVar的十六进制(大写):%#X\n", octalVar); //0x7B
// 打印hexVar的十进制、八进制、十六进制(小写和大写)
printf("hexVar的十进制:%d\n", hexVar); //123
printf("hexVar的八进制:%#o\n", hexVar); //0173
printf("hexVar的十六进制(小写):%#x\n", hexVar); //0x7b
printf("hexVar的十六进制(大写):%#X\n", hexVar); //0x7B
// 打印hexVarUpper的十进制、八进制、十六进制(小写和大写)
// 注意:hexVarUpper和hexVar在数值上是相同的,所以它们的输出也会相同
printf("hexVarUpper的十进制:%d\n", hexVarUpper); //123
printf("hexVarUpper的八进制:%#o\n", hexVarUpper); //0173
printf("hexVarUpper的十六进制(小写):%#x\n", hexVarUpper); //0x7b
printf("hexVarUpper的十六进制(大写):%#X\n", hexVarUpper); //0x7B
return 0;
}
3 进制转换
3.1 任意进制转十进制
方法:系数 * 基数权次幂 相加
- 系数:就是每一位上的数据。
- 基数:几进制,基数就是几。
- 权 : 数位从右往左,0开始编号,对应位上的编号即为该位的权。
- 结果:把系数 * 基数的权次幂相加即可。
3.1.1 二进制转十进制
8421快速转换法:
3.1.2 八进制转十进制
3.1.3 十六进制转十进制
0、1、2、3、4、5、6、7、8、9、 A(10) 、B(11)、C(12)、D(13)、E(14)、F(15)
3.2 十进制转换其他进制
3.2.1 转换为整数
方法:除基取余(直到商为0停止),逆序排序(余数)
以十进制转二进制为例:
3.2.2 转换为小数
方法:乘基取整(直到小数部分为0,或取到对应有效位停止),顺序排序(整数部)
3.3 二进制与八进制互转
3.3.1 二进制转八进制
取三合一法,即从二进制的小数点为分界点,向左(向右)每三位取成一位,不足补0,接着将这三位二进制按权相加,得到的数就是一位八位二进制数,然后,按顺序进行排列,小数点的位置不变,得到的数字就是对应的八进制数。
将 0b101110.101 转换为八进制为 56.5
将 0b1101.1 转换为八进制为 15.4
3.3.2 八进制转二进制
取一分三法,即将一位八进制数分解成三位二进制数,用三位二进制按权相加去凑这位八进制数,小数点位置照旧。上面的逆运算。
3.4 二进制与十六进制互转
3.4.1 二进制转十六进制
取四合一法,即从二进制的小数点为分界点,向左(向右)每四位取成一位,不足补0,接着将这四位二进制按权相加,得到的数就是一个十六位二进制数,然后,按顺序进行排列,小数点的位置不变,得到的数字就是对应的十六进制数。
3.4.2 十六进制转二进制
取一分四法,即将一位十六进制数分解成四位二进制数,用四位二进制按权相加去凑这位十六进制数,小数点位置照旧。上面的逆运算。
3.5 八进制与十六进制互转
遇到较为复杂的转换,其实都可以使用二进制作为跳板。
3.5.1 八进制转十六进制
如八进制转换为十六进制,可先将八进制转换成二进制(取一分三),再用得到的二进制转换成十六进制(取四合一)即可。
3.5.2 十六进制转八进制
同理,十六进制转换成八进制,可先将十六进制转换成二(取一分四)进制,再用得到的二进制转换成八进制(取三合一)即可。
3.6 通过计算器辅助转换:
手动转换一个数的进制后,若不知道转换后的进制数是否正确,则可在 Windows 操作系统下选择“开始”→“计算器”,打开“计算器”。
或者 win + r 运行框中输入:calc ,即calculate的简写:
然后选择菜单项“查看”→“程序员”,得到如下图所示的计算器。输入一个十进制数后,单击“十六进制”“八进制”或“二进制”,即可得到对应进制的转换结果。
4 Clion查看变量内存视图
输入以下代码:
#include <stdio.h>
int main() {
int i = 123;
printf("十进制:%d\n", i); //十进制:123
printf("八进制:%#o\n", i); //八进制:0173
printf("十六进制:%#x\n", i);//十六进制:0x7b
printf("十六进制:%#X\n", i);//十六进制:0X7B
return 0;
}
开始调试模式:
点击步过:
目前我们执行到语句 int i = 123 ,变量 i 会在内存上被分配空间,大小为 4 字节,会看到如上图所示,其中 i 的值变为 7b (我们以十六进制方式查看内存),其十进制值为 7×16 + 11 = 123 。i 的值是 0x0000007b 。为什么显示结果为 7b 00 00 00 呢?原因是英特尔的 CPU 采用了小端方式进行数据存储,因此低位在前、高位在后。
5 大端字节序和小端字节序
大端字节序(Big-Endian):在这种字节序中,数据的高位字节存储在内存的低地址端,而低位字节存储在内存的高地址端。这意味着,从内存的低地址到高地址,数据的字节顺序与它们从高位到低位的顺序相同。
小端字节序(Little-Endian):与大端字节序相反,小端字节序中,数据的低位字节存储在内存的低地址端,而高位字节存储在内存的高地址端。这意味着,从内存的低地址到高地址,数据的字节顺序与它们从低位到高位的顺序相同。
以十六进制数 5c 6e c9 57 为例:
- 大端字节序:内存地址从低到高(从左到右):57 c9 6e 5c
- 小端字节序:内存地址从低到高(从左到右):5c 6e c9 57
注意:一个字节上的数据不要写反了,如 5c 不要写成 c5 。
5c 6e c9 57小端字节序存储示例:
6 练习
1、程序运行时,整型是以二进制在内存中存储的,十进制、八进制、十六进制是为了人类使用而设计的?
A. 正确 B. 错误 答案:A
解释:正确的,这个需要记住。计算机只能识别 0 和 1,其他进制的设计是为了方便我们使用。
2、十进制是 0 - 9,八进制是 0 - 8,十六进制是 0 - 9、A - F,请问是否正确?
A. 正确 B. 错误 答案:B
解释:八进制是 0 - 7,总计 8 种变化情况,并不是 0 - 8。
3、整型数 124 对应的十六进制值是 0x7c?
A. 正确 B. 错误 答案:A
解释:把一个 10 转为 16 进制,只要不断除 16 即可。124 除 16,商是 7,余数是 12,而 12 就是 c,因此是 0x7c。