第十二章:C 内存模型
级别 2 — 认知
对象、字节、联合体、有效类型、对齐——最深的 C 内部机制。
这是本书技术密度最高的一章。C 内存模型定义了数据如何存储、访问和在字节级别解释。理解它对于编写正确的底层 C 以及欣赏 Auto 抽象了什么都至关重要。
12.1 统一内存模型
在 C 中,所有数据——整数、浮点数、结构体、数组——都作为连续的字节序列存储。每个字节有唯一地址,内存中的每个对象都可以作为原始字节检查。
c
// C 深入:对象表示
int x = 42;
unsigned char *bytes = (unsigned char*)&x;
printf("Byte 0: 0x%02x\n", bytes[0]);
printf("Byte 1: 0x%02x\n", bytes[1]);
// 小端序:0x2a, 0x00(对于 int32)关键概念:
- 对象:保存特定类型值的存储区域。
- 表示:编码该值的字节序列。
sizeof:对象占用的字节数。
c
// C 深入:常见类型的大小
printf("sizeof(char): %zu\n", sizeof(char)); // 始终为 1
printf("sizeof(int): %zu\n", sizeof(int)); // 通常为 4
printf("sizeof(float): %zu\n", sizeof(float)); // 通常为 4
printf("sizeof(double): %zu\n", sizeof(double)); // 通常为 8
printf("sizeof(int*): %zu\n", sizeof(int*)); // 4 或 8类型的大小决定了指针算术前进多少字节。sizeof(char) 根据定义始终为 1——它是 C 中存储的基本单位。
C 深入: C 保证任何对象都可以使用
memcpy逐字节复制。这是序列化和反序列化的基础。Auto 对其值类型提供相同的保证。
12.2 联合体
联合体是一种所有成员共享相同内存位置的类型。联合体的大小等于其最大成员的大小:
c
// C 深入:联合体
union Value {
int i;
float f;
char s[16];
};
union Value v;
v.i = 42; // 以 int 存储
printf("%d\n", v.i); // 以 int 读取:42
v.f = 3.14f; // 以 float 覆盖
printf("%f\n", v.f); // 以 float 读取:3.14
// printf("%d\n", v.i); // 未定义行为:类型错误!从非最后写入的成员读取在标准 C 中是未定义行为(符号变体有例外)。这使得裸联合体很危险。
标签联合体通过将判别符(标签)与联合体配对解决了这个问题:
c
// C 深入:标签联合体
enum ValueType { VAL_INT, VAL_FLOAT, VAL_STRING };
struct TaggedValue {
enum ValueType tag;
union {
int i;
float f;
char s[16];
} data;
};
void describe(struct TaggedValue v) {
switch (v.tag) {
case VAL_INT: printf("integer: %d\n", v.data.i); break;
case VAL_FLOAT: printf("float: %f\n", v.data.f); break;
case VAL_STRING: printf("string: %s\n", v.data.s); break;
}
}Auto 的替代:带数据的 enum。 Auto 将标签联合体作为一等特性提供,消除了手动管理:
auto
enum Value {
IntVal int
FloatVal float
StrVal str
}
fn describe(v Value) str {
is v {
IntVal(n) => "integer: " + str(n)
FloatVal(f) => "float: " + str(f)
StrVal(s) => "string: " + s
}
}