fread返回0的常见原因是文件未成功打开或未以二进制模式打开:fopen需用"rb",std::ifstream需加std::ios::binary;读取后必须检查fread返回值是否为4,而非仅依赖ferror()。

读取前4字节判断 Magic Number 时,为什么 fread 返回值总为0?
常见错误是没检查文件是否成功打开、是否以二进制模式打开。C++ 中用 fopen 读二进制文件,必须显式指定 "rb" 模式;用 std::ifstream 则必须加 std::ios::binary 标志,否则 Windows 下遇到 0x1A(EOF)会提前截断。
-
fopen("file.bin", "r")→ 错,文本模式会误转义换行和 Ctrl+Z -
std::ifstream f("file.bin")→ 错,缺std::ios::binary,Linux 可能侥幸,Windows 必崩 - 用
fread(buf, 1, 4, fp)后,必须检查返回值是否等于 4,不能只看ferror() - 缓冲区
buf要确保至少 4 字节,且未初始化不影响判断(直接比对字节即可)
对比 Magic Number 时,memcmp 和逐字节比较哪个更安全?
二者都行,但 memcmp 更简洁、不易漏判;唯一陷阱是传入的字节数必须严格匹配 Magic 长度,且目标内存不能越界。比如 PNG 的 89 50 4E 47 0D 0A 1A 0A 是 8 字节,传 4 就只校验了前半段,可能误判。
- 推荐用
memcmp(buf, "\x89\x50\x4E\x47", 4)判断 PNG 开头,字符串字面量自动带 \0,但memcmp不依赖它 - 避免写
if (buf[0] == 0x89 && buf[1] == 0x50 ...),代码冗长还容易写错下标 - 若 Magic 含可变字段(如 ELF 的第 5 字节是 class,32/64 位不同),就不能硬比全部字节,得拆开判断
用 std::ifstream 读 Magic 时,read() 失败却不报错?
因为 read() 不抛异常,默认关闭异常位;调用后必须手动查 gcount() 或 fail(),否则静默失败。
std::ifstream f("data.bin", std::ios::binary); char buf[4]; f.read(buf, 4);- 立刻跟一句
if (f.gcount() != 4) { /* 实际只读了0或2字节 */ } - 不建议依赖
!f或f.fail(),它们在部分平台对短读不触发(尤其文件末尾) - 如果后续还要读文件其余内容,别忘了
f.seekg(0)回到开头,否则位置指针已偏移
常见格式 Magic Number 对照表(含易混淆点)
很多 Magic 看似相似,但一字之差就不是同一类文件。例如 0x7F 'E' 'L' 'F' 是 ELF,而 0x46 'L' 'E' 0x7F 是倒序——实际不存在,但手抖写反就会永远不匹配。
立即学习“C++免费学习笔记(深入)”;
- ELF:
7F 45 4C 46(注意是小端存储,但 Magic 本身按字节流顺序存) - PE(Windows EXE):
4D 5A("MZ")开头,但完整 Magic 是4D 5A ?? ?? 00 00 00 00,第3–4字节是 DOS stub 长度,不固定 - ZIP:
50 4B 03 04或50 4B 05 06(空 ZIP)或50 4B 07 08(分卷),不能只认前两字节 - PDF:
25 50 44 46 2D 31 2E("%PDF-1."),注意 ASCII 字符,不是纯数值比较
Magic 不是银弹:有些格式(如某些自定义协议或加密容器)根本没 Magic,或者 Magic 被加密/混淆。真要鲁棒识别,得结合文件扩展名、内部结构校验、甚至尝试解析关键字段。



















