我有一个最近在1990年编译的C程序,它读取和写入一些二进制文件。可执行文件仍然可以正常工作,读取和写入它们。我需要重新编译源代码,添加一些功能,然后使用代码,读取一些旧数据,并输出其他信息。
当我重新编译代码而没有更改并执行它时,它无法读取旧文件,当我尝试处理读入内存区域的数据时出现分段错误。我认为问题可能是前面写的二进制文件使用4个8位字节整数,8个字节长整数和4个字节浮点数。我的机器上的体系结构现在使用64位字而不是32字节。因此,当我从读入的数据中提取一个整数时,它被错误地对齐并设置了一个超出程序空间范围的数组索引。
在Mac OS X 10.12.6上,使用其编译器,可能是:
Apple LLVM version 8.0.0 (clang-800.0.33.1)
Target: x86_64-apple-darwin16.7.0
是否有编译器开关将整数和浮点数的编译长度设置为上述值?如果没有,我如何让代码正确读取数据?
答案 0 :(得分:8)
欢迎来到便携头痛的世界!
如果您的程序是在1990年编译的,那么它很可能使用4个字节long
,甚至可能使用2个字节int
,具体取决于它编译的体系结构对
基本C类型的大小在很大程度上依赖于系统,在许多更微妙的可移植性问题中。 long
现在在64位Linux和64位OS / X上都是64位,但在Windows上仍然是32位(对于32位和64位版本!)。
读取二进制文件时,你还必须处理endianness,它从1990年MacOS的big-endian变为今天的OS / X的little-endian,但在其他系统上仍然是big-endian。
更糟糕的是,C语言经过这么长时间的演变,并且在ANSI C和标准C之间发生了一些非平凡的语义变化。不再支持一些旧的语法......
没有神奇的旗帜可以解决这些问题,您需要深入了解C代码并了解其作用,并尝试对代码进行现代化,使其更具可移植性,独立于目标架构。您可以使用<stdint.h>
中的固定宽度类型来简化此过程(int32_t
,...)。
人们在Stackoverflow上回答C问题通常会谨慎发布适用于所有目标体系结构的可移植代码,甚至是一些有意识的恶意代码,例如DS9K(以正确但意想不到的方式执行所有操作的虚拟计算机)