1990 年编写的 C 代码可执行运行。现在重新编译,它在旧文件上出现读取错误

C code written in 1990 executable runs. Recompiled now, it gets read errors on old file

我有一个最后编译于 1990 年的 C 程序,它读写一些二进制文件。可执行文件仍然有效,可以完美地读取和写入它们。我需要重新编译源代码,添加一些功能,然后使用代码,读取一些旧数据,并输出附加信息。

当我重新编译代码(不做任何更改)并执行它时,它无法读取旧文件,当我尝试处理读入内存区域的数据时出现分段错误。我认为问题可能出在之前编写的二进制文件使用了 4 个 8 位字节整数、8 字节长型和 4 字节浮点数。我机器上的体系结构现在使用 64 位字而不是 32 位字。因此,当我从读入的数据中提取一个整数时,它没有正确对齐并设置了一个超出程序范围的数组索引 space。

在 Mac OS X 10.12.6 上,使用其 C 编译器可能是:

Apple LLVM version 8.0.0 (clang-800.0.33.1)
Target: x86_64-apple-darwin16.7.0

是否有编译器开关可以将整数和浮点数的编译长度设置为上述值?如果没有,我如何让代码正确读取数据?

欢迎来到令人头疼的便携性世界!

如果你的程序是在 1990 年编译的,它很有可能使用 4 字节 longs,甚至有可能使用 2 字节 int,这取决于它的架构编译为.

基本 C 类型的大小在很大程度上取决于系统,还有许多更微妙的可移植性问题。 long 现在在 64 位 linux 和 64 位 OS/X 上都是 64 位的,但在 Windows 上仍然是 32 位(对于 32 位和 64-位版本!)。

读取二进制文件,还必须处理字节序,从1990年MacOS的big-endian变为今天OS/X的little-endian,但在其他系统上仍然是big-endian

更糟糕的是,C 语言在这么长的时间里不断发展,在 ANSI C 之前的版本和标准 C 之间发生了一些重要的语义变化。一些旧语法也不再受支持...

没有解决这些问题的神奇标志,您需要深入研究 C 代码并了解它的作用,并尝试使代码现代化并使其更易于移植,独立于目标体系结构。您可以使用 <stdint.h> 中的固定宽度类型来简化此过程 (int32_t, ...)。

在 Whosebug 上回答 C 问题的人通常会小心 post 可移植代码,这些代码可以在所有目标体系结构上正常工作,甚至是一些故意恶意的代码,例如 DS9K(一台虚构的计算机,可以做所有事情以正确但意想不到的方式)。