这段代码我最大的问题是在这一行:
fread (buffer,sizeof(int),4000000,fp);
实际上,这一行引入了一系列重要的问题。首先,不能保证您正在读取的文件已成功打开。正如其他人所指出的那样,您需要进行比较fp
才能NULL
做出保证。其次,我似乎经常强调这种方式:你真的应该检查 return value。这适用于所有标准 C 函数,而不仅仅是fopen和fread。
fread的返回值告诉您实际读取了多少项目。假设您请求 400 万个int
s,而该文件仅包含两个。返回值会告诉你只int
读取了两个 s。
现在,进入大事!让我们首先考虑sizeof(int)
在不同的实现上有所不同。您的系统可能会读取 4 个字节,而另一个可能会读取 2 个字节,而另一个可能会读取 8 个字节。这只是整数表示可能不同的基本但基本方式。
让我们考虑一种更微妙但同样具有破坏性的整数表示可能不同的方式:假设您int
的 s 是四个字节,最左边的位是最低有效位。另一台机器可能使用最左边的位作为最低有效位。同样,考虑字节顺序,即字节顺序。
假设您int
的 s 是 32 位,它们代表 和 之间的值-(1 << 31)
,(1 << 31)
这意味着没有填充位。另一个系统可能使用具有 16 位填充的 32 位整数,这意味着它可能只表示 和 之间的-(1 << 16)
值(1 << 16)
。假设这些填充位是奇偶校验位,以确保 RAM 正常运行(例如 Intel Xeon 服务器)。现在,您的服务器会告诉您 RAM 有故障,而实际上并非如此。
您的代码应明确地将文件用于存储整数的整数表示转换为计算机本机使用的任何表示。将整数写入文件时,您需要确保将实现表示明确转换为该表示。同样,当从文件中读回整数时,您的代码应该将该表示显式转换为您的实现表示。
例如,让我们假设您的int
值不会超出-32767
或32767
(16 位有符号整数,一个的补码)。使用两个字节表示它是可移植的,但您需要明确定义该整数的符号和表示。写入时,您可以提取符号和绝对值,然后写入sign * 128 + absolute_value / 256
文件absolute_value % 256
。阅读时,您将提取符号位,乘以并添加以重建您的值。
让我们考虑一下您的文件应该是 4MB,但您正在读取sizeof (int) * 4000000
值。4MB 是0x400000
,不是sizeof (int) * 4000000
。我想您真正想要的是以下内容:
unsigned char *foo = malloc(0x400000); /* 4MB */
/* XXX: Handle malloc errors here */
assert(foo != NULL);
FILE *fp = fopen("file.bin", "rb");
/* XXX: Handle fopen errors here */
assert(fp != NULL);
size_t num_bytes_read = fread(foo, 1, 0x400000, fp);
/* XXX: Transform the bytes into integers */
free(foo);
我的问题是它依赖一个 4MB 的缓冲区来读取字节并将其转换为整数。这个任务根本不需要缓冲区!
FILE *fp = fopen("file.bin", "rb");
/* XXX: Handle fopen errors here */
assert(fp != NULL);
for (;;) {
int x = fgetc(fp);
/* XXX: Handle fgetc errors here */
assert(x >= 0);
int y = fgetc(fp);
/* XXX: Handle fgetc errors here */
assert(y >= 0);
/* XXX: Transform the characters in x and y into the int values */
};
free(foo);
问题中未指定您是否需要将这些转换后的值存储在某处。如果您不需要,那么我的下一个问题是数组的使用,当您可能只是读取单个项目,处理它然后移动到下一个项目时。