02_信息的表示和存储
现代计算机存储和处理的信息以二值信号表示,这些二进制数字称为位(bit).把位组合在一起,再加上某种解释,就能够表示任何有限集合的元素。
信息存储
大多数计算机使用8位的块,或者字节(byte),作为最小的可寻址的内存单位,而不是访问内存中单独的位。程序将内存视为一个非常大的字节数组,称为虚拟内存(virtual memory).内存的每个字节都有唯一的数字来标识,称为它的地址(address),所有可能地址的集合就称为虚拟地址空间(virtual address space).每个程序对象可以简单地视为一个字节块,而程序本身就是一个字节序列。
每台计算机都有一个字长(word size),指明指针数据的标称大小(nominal size)。字长决定虚拟地址空间的最大大小。对于一个字长为 w 位的机器而言,程序最多访问 2w 个字节。大多数64位机器也可以运行为32位机器编译的程序,这是一种向后兼容。
// 32位程序
linux> gcc -m32 prog.c
// 64位程序
linux> gcc -m64 prog.c
大部分机器上,多字节对象都被存储位连续的字节序列,对象的地址为所使用字节中最小的地址。某些机器在内存中按照从最低有效字节到最高有效字节的顺序存储对象,称为小端法(little endian);另一些机器按照从最高有效字节到最低有效字节的顺序存储,称为大端法(big endian).
假设变量x 的类型为 int,位于地址 0x100 处,它的十进制为 0x01234567,地址范围 0x100~0x103的字节顺序依赖于机器的类型:
在不同类型的机器之间通过网络传送二进制数据时,当小端法机器产生的数据被发送到大端法机器或者反过来时,接收程序会发现字节成了反序的。
#include
// 指向类型为 unsigned char 的对象的指针
typedef unsigned char *byte_pointer;
void show_bytes(byte_pointer start, size_t len)
{
size_t i;
for(i = 0; i < len; i++)
{
printf(" %.2x", start[i]);
}
printf("\n");
}
void show_int(int x)
{
// 强制转换成字节序列
show_bytes((byte_pointer)&x, sizeof(int));
}
void show_float(float x)
{
show_bytes((byte_pointer)&x, sizeof(float));
}
void show_pointer(void* x)
{
show_bytes((byte_pointer)&x, sizeof(void*));
}
void test_show_bytes(int val)
{
int ivale = val;
float fval = (float)ival;
int *pval = ival;
show_int(ival);
show_float(fval);
show_pointer(pval);
}
在不同机器上输出结果如下:
可以看出,对于int和float类型除了自己顺序外,在所有机器上得到相同结果。但,指针是完全不同的,不同机器/操作系统配置使用不同的存储分配规则。
对于字符串,C语言中编码为一个以 null 字符结尾的字符数组,每个字符都有某个标准编码来表示,最常见的是 ASCII 字符码。文本数据比二进制数据具有更强的平台独立性。
整数表示
有符号数的计算机表示方式最常见的就是补码形式,最高有效位也成为符号位.
w位补码所能表示的范围,最小值向量[10...0],对应整数值为 -2w-1 ;最大值向量[01...1],对应整数值为 2w-1-1.
大多数C语言的实现,处理同样字长的有符号数和无符号数之间相互转换的一般规则是:数值可能会改变,但是位模式不变。
补码转换为无符号数的规则如下:
无符号数转换为补码的规则如下:
整数运算