02 Storage
这篇笔记包含lecture3 information storage相关的内容。
指针和字符大小
到底哪里提到了指针,address吗
读写操作
wirte操作类似 write(name, value) 。这说明使用write需要指定两个值:要写入的值(value)、可以追溯到这个值的名称(name)。类似地,read操作需要要读出的名称(name)和内存设备。
内存
内存是存储设备之一。在内存中,数据的存储大小(size)是固定的,而名称(name)是从0开始的一系列整数,这些整数称作地址(address),整个集合称作地址空间(address space)。
字符大小
虚拟地址通过固定大小(size)的字符编码。这里的字符大小代表相应种类的字符大小,决定了虚拟地址空间的最大值,也决定了最重要的系统参数。
对于 位机器,虚拟地址的取值可以从 到 。目前的机器大多为64位(8字节),也支持32位(32位将地址限制到4GB)。
下表列出了32位和64位机器中,不同类型所占的位数。

除此之外,还有 intN_t 和 uintN_t 。这一类数据类型在 stdint.h 中,包含 int8_t 、 int16_t 、 int32_t 、 int64_t 和 uint8_t 、 uint16_t 、 uint32_t 、 uint64_t 。
程序可能因为机器位数不同出现bug。C为不同数据类型的数据范围设置了下限,但没有上限。在32位机器上正常工作的程序可能会在64位机器上出问题。
字节顺序
虚拟内存
前文提到的内存只是虚拟概念,实际并不存在,只是概念上的图像。事实上,虚拟内存是由软硬件的一系列配合搭建的。

可以将虚拟内存划分为不同部分。

字节顺序
在不同芯片中,LSB的位置不同。在big endian中(如Intel),LSB地址最低;在little endian中,LSB地址最高。即,对于 int 变量 a ,若 p 为 a 的地址,big endian会把 p 作为高位,little endian会把 p + 3 作为高位(但是读取范围都是 p 到 p + 3 )。
这个程序会在little-endian机器上返回1,在big-endian机器返回0。
int is_little_endian(void) {
int x = 1;
return (int)(*(char*)&x);
// 原答案为 !(1 - (int)(*(char*)&x))
}
( void 表示没有任何参数)
C语言中的对象被简单地视作字节块,而对象指针的值是字节块中第一个字节的虚拟地址。编译器会为不同类型的指针生成不同的机器码(事实上机器码中不含有数据类型的信息)。不同机器可能把LSB放在不同的位置,同一个数据存储会有不同顺序,可能导致错误。显示的显现出字节顺序不过这跟强制类型转换有什么关系,可以让不同机器之间通信。
下面的代码可以将任意整数转为little-endian表示。
byte *to_little_endian(unsigned int num) {
byte *ret = (byte *)malloc(sizeof(int));
if (is_little_endian()) {
memcpy(ret, &num, sizeof(int));
} else {
byte *bytes = (byte *)#
ret[0] = byte[3];
ret[1] = byte[2];
ret[2] = byte[1];
ret[3] = byte[0];
}
return ret;
}
对于字符串,由于每个字符只占一字节,字节顺序 就不是问题。不过,不同机器的结束符可能不同(linux为00)。
下面是一段打印byte representation的代码。
typedef unsigned char *byte_pointer;
void show_bytes(byte_pointer start, int len)
{
int i;
for (i = 0; i < len; i++) {
printf("0x%p\t0x%.2x\n", start + i, start[i]);
}
printf("\n");
}
其中, %p 用于打印指针, %.2x 打印至少输出两位的16进制。