Appearance
题目
某 32 位计算机按字节编址,采用小端方式存放数据,编译器按边界对齐方式为下列 C 语言结构型数组变量 employee 分配储存空间。
c
struct record {
int id;
char name[10];
int salary;
} employee[200];数组 employee 的起始地址为 0000A0B0H,employee[1].id 的机器数为 12345678H,问 56H 的地址是多少?( )。
错因
A
完全忽略了对齐填充——把结构体大小算成 4 + 10 + 4 = 18 字节。于是 employee[1] 起始地址 = A0B0H + 18 = A0C2H,再去算 56H 在 id 内的偏移(小端把 56H 放到 +1 字节)= A0C3H。错点是没意识到 int salary 必须按 4 字节边界对齐:name[10] 占完后下一个空位是偏移 14(不是 4 的倍数),编译器要插 2 字节填充再放 salary。
B
对齐和数组步长都对了——算出 employee[1] 起始 = A0C4H,但忘了小端,把 56H 当成 12345678H 的最高字节"放在最低地址"。这其实是大端思路:低地址放高字节、12 在 A0C4H、56 在 A0C6H。题目明说"小端",56H 在中间偏低位置(+1 字节)才对。
D
也是把小端 / 大端搞反的另一种走样:知道要算 56H 在 4 字节字内的偏移,但把字节顺序写成"低地址放高字节"(大端),又选了对应大端的"中位高字节"地址 A0C6H。总之 D 的人和 B 的人犯的是同一类错——把 12345678H 的字节序按大端摆——只是把 56H 当成第 2 字节(B 的人当第 0 字节)而已。
总解析
思路:本题三个独立步骤,每一步错了都到不了正确答案——
- 算单个 record 的对齐后大小(含填充)
- 用对齐大小×下标求 employee[1] 的起始地址
- 用小端字节序在 4 字节字内定位 56H
第一步:record 的对齐布局
成员对齐规则:每个成员的起始偏移必须是其类型大小的整数倍(标准 GCC/MSVC 默认行为)。结构体整体大小要按"最大对齐"(这里是 int 的 4)向上取整,方便数组步长。
逐字节走一遍:
| 偏移(字节) | 内容 | 说明 |
|---|---|---|
| 0–3 | int id(4B) | 起始偏移 0 ✓ 对齐 4 |
| 4–13 | char name[10](10B) | char 对齐 1,紧接 |
| 14–15 | 填充 2B | 下一个 int 起始要是 4 的倍数;14 不是,跳到 16 |
| 16–19 | int salary(4B) | 偏移 16 ✓ 对齐 4 |
| 共 20 字节 | 已经是最大对齐 4 的倍数,不再尾部填充 |
所以 sizeof(struct record) = 20 = 0x14。
第二步:employee[1] 的起始地址
数组起始 = 0000A0B0H,每元素 20 字节:
employee[1].id 的偏移仍为 0,所以它占据 A0C4H ~ A0C7H 共 4 字节。
第三步:在 4 字节字里小端定位 56H
employee[1].id 的机器数 = 12345678H = 0001 0010 0011 0100 0101 0110 0111 1000。按字节切:
| 字节 | 12 | 34 | 56 | 78 |
|---|---|---|---|---|
| 在数值中位置 | 最高字节(B3) | 次高(B2) | 次低(B1) | 最低字节(B0) |
小端:"最低字节存最低地址"。所以从 A0C4H 起依次摆 78、56、34、12:
| 地址 | A0C4H | A0C5H | A0C6H | A0C7H |
|---|---|---|---|---|
| 字节内容 | 78H | 56H | 34H | 12H |
56H 的地址 = A0C5H。
最终答案是 C(0000 A0C5H)。
结构体地址题三步速记:
| 步骤 | 该问 | 易错 |
|---|---|---|
| 1. 算 sizeof | 各成员对齐填充 + 尾部填充到最大对齐 | 忘填充、按 4+10+4=18 算 |
| 2. 算第 i 个起点 | 起始地址 + i × sizeof | sizeof 算错就连环错 |
| 3. 字内定位字节 | 小端:低字节低地址 | 把大端当小端 |
口诀:先填对齐再算步长,最后按小端摆字节。