16.2 对象表示
本节介绍对象表示 (Object representation) 与值表示 (Value representation)。
你可以把它们理解为:
- 对象表示:对象在内存(抽象机器的字节序列)中的“原始字节形态”。
- 值表示:在这些字节形态中,哪些位模式 (Bit pattern) 对应“有效的值”。
借助这一区分可以说明:某些类型的部分位模式不表示该类型的任何值,即陷阱表示 (Trap representation);结构体中还可能出现不属于任何成员的填充字节 (Padding)。
1. 对象表示 vs 值表示
1.1 对象表示 (Object representation)
对象表示是对象占据的那段连续字节的内容。标准允许你通过字符类型(char、signed char、unsigned char)观察并复制对象表示。
1.2 值表示 (Value representation) 与填充位
对某些类型而言,并非所有位模式都对应一个合法值:
- 某些位可能是填充位 (Padding bit);
- 某些位模式可能是陷阱表示 (Trap representation)。
当一个对象的对象表示对应陷阱表示时,对该对象按其类型进行求值(读出“值”)可能触发 UB。
实践建议
除非你确实在做底层库(序列化、校验、哈希、协议),否则应尽量避免依赖“具体对象表示”。对象表示通常是实现定义的(例如大小端、浮点格式)。
2. 观察对象表示:标准写法
2.1 使用 unsigned char 查看字节
#include <stddef.h>
#include <stdio.h>
static void dump_bytes(const void* p, size_t n) {
const unsigned char* b = (const unsigned char*)p;
for (size_t i = 0; i < n; i++) {
printf("%02x%s", (unsigned)b[i], (i + 1 == n) ? "" : " ");
}
putchar('\n');
}
int main(void) {
unsigned x = 0x11223344u;
dump_bytes(&x, sizeof x);
return 0;
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
在 CHAR_BIT 为 8、unsigned 为 32 位的常见实现中,小端序和大端序会分别得到:
44 33 22 1111 22 33 44输出取决于字节序 (Endianness),若 unsigned 的宽度不同,字节数也会随之变化。字节序属于实现定义行为 (Implementation-defined behavior)。
2.2 使用 memcpy 在类型之间搬运对象表示
需要把某个对象的对象表示按另一种类型解释时,应使用 memcpy 复制字节,而不是把指针转换类型后解引用。
示例见 16.1 内存模型 中的 float / uint32_t 示例。
3. 对齐相关
对象表示与对齐密切相关:对齐决定了对象能出现在哪些地址上,也影响结构体内部的填充布局。
4. 习题
写程序分别观察 uint16_t、uint32_t、uint64_t 的字节序输出,并总结你的平台是大端还是小端。
写程序观察以下类型的 sizeof 与 alignof(见 16.2.2):char、int、double、max_align_t。
设计一个“结构体布局观察”实验:对 struct { char a; int b; char c; } 输出:
sizeof;offsetof(需要<stddef.h>);- 对象表示(建议先把对象整体置零,再写入成员值)。
使用 unsigned char 访问对象表示,实现:
#include <stddef.h>
void *mdr_memset(void *dest, int ch, size_t count);2
3
把 ch 转换为 unsigned char 后写入 dest 指向区域的前 count 个字节,并返回 dest。调用方保证该区域至少包含 count 个可写字节;不得调用 <string.h> 中的函数。
使用 unsigned char 访问对象表示,实现:
#include <stddef.h>
void *mdr_memcpy(void *restrict dest, const void *restrict src, size_t count);2
3
复制恰好 count 个字节并返回 dest。调用方保证源区域和目标区域均足够大且不重叠;不得调用 <string.h> 中的函数。再编写测试,覆盖 count == 0、单字节复制和多字节复制。