大小端字节序与 magic number:union 实验与文件读取

Guo Xiaosheng Lv1

在开发机上读取 MNIST idx 文件(大端格式)时涉及字节序与文件格式识别问题,记录如下。

定义

多字节数据在内存或文件中的字节排列顺序称为字节序,分两种:

  • 大端(big-endian):高位字节在前
  • 小端(little-endian):低位字节在前

0x12345678 为例,4 个字节从前到后的排列:

字节序 第1字节 第2字节 第3字节 第4字节
大端 12 34 56 78
小端 78 56 34 12

常见约定

  • ARM 默认小端,x86 小端。开发机(Windows PC)为小端。
  • Modbus、TCP/IP 协议为大端。

magic number

magic number 是文件开头固定的几个字节,用于标识文件格式。程序靠它识别文件类型,人靠扩展名。

文件 开头字节 含义
PNG 89 50 4E 47 “PNG” 的 ASCII
EXE 4D 5A “MZ”
MNIST 图片 idx 00 00 08 03 unsigned byte,3 维
MNIST 标签 idx 00 00 08 01 unsigned byte,1 维

程序先读 magic,验证格式后再继续读数据。

idx 的 magic 按大端读是一个整数,其低两个字节有编码含义:

1
2
3
4
0x00000803
└┬┘└┬┘
│ └── 维度数 = 3(图片为 [60000][28][28])
└───── 数据类型 = 0x08(unsigned byte)

图片 magic 对应整数 2051(0x0803),标签 magic 对应 2049(0x0801)。

小端机器读取大端文件

图片文件前 4 字节为 00 00 08 03(大端)。若小端机器直接 freadintfread 本身不做任何转换,只是把这 4 字节原样拷入内存;颠倒发生在 CPU 按小端解释这段内存时——低地址的 00 被当作最低字节,整数值变为 0x03080000 = 50,855,936,不是 2051。

需手动拼字节:

1
2
3
unsigned char b[4];
fread(b, 1, 4, fp);
int magic = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];

b[0] 是大端中的最高字节,对应移位 << 24。代入 00 00 08 03

1
2
3
magic = (0x00<<24) | (0x00<<16) | (0x08<<8) | 0x03
= 0x00000803
= 2051 /* 正确 */

此写法即手动实现大端读取。读取 idx 的 magic 和后续维度都应采用。

用 union 检测字节序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>

union
{
short name;
char age[2];
} li;

int main()
{
li.name = 1234; /* 0x04D2 */
printf("%x%x", li.age[0], li.age[1]);
return 0;
}

union 各成员共享同一块内存,写入与读取针对同一地址。

赋值 字节序 age[0] age[1] 输出
li.name = 0x04D2 小端 D2 04 d204
li.name = 0x04D2 大端 04 D2 04d2
li.name = 0x1234 小端 34 12 3412
li.name = 0x1234 大端 12 34 1234

输出结果即机器字节序。开发机输出 d204,为小端。

注意:%x 配 char 的符号扩展

上例低字节 0xD2 ≥ 0x80,在 signed char 下为负数。传给 printf 时整型提升为 int,负数符号扩展成 0xFFFFFFD2%x 输出一长串而非 d2

应显式转为 unsigned char,并用 %02x 保证补零:

1
printf("%02x %02x", (unsigned char)li.age[0], (unsigned char)li.age[1]);

小结

大小端只决定多字节数的排列方式,无对错。小端机器读大端文件,需要手动拼字节或显式做字节交换。读取 idx 的 magic 和维度时应使用上述拼字节方式,并先校验 magic 是否合法。

  • 标题: 大小端字节序与 magic number:union 实验与文件读取
  • 作者: Guo Xiaosheng
  • 创建于 : 2026-08-03 21:10:00
  • 更新于 : 2026-08-04 00:20:28
  • 链接: https://serendipityb612.com/2026/08/03/2026-08-03-endianness-and-union/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。