存储在二进制文件中的 int 的 fread() 失败,分段错误
Unsuccessful fread() of int stored in binary file, segmentation fault
似乎有大约 10 个问题和(大部分)成功的答案解决了 C 中错误使用 fread() 导致的分段错误。也就是说,我遇到了这样的问题,但还没有找到解决方案。
我有一个二进制文件,其中包含一个 int
(称之为 nbins)和一个 float
数组(大小为 nbins)。当我尝试读取此文件时,它成功打开并指向文件句柄,但在读取 nbins int
时出现分段错误。这是一个最小的例子:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BPATH "/path/to/file"
int main(int agrc, char **argv)
{
FILE *fd;
int num;
char fname[500]={};
int nbins;
float *coords;
num = 5;
sprintf(fname,"%s/file%d.dat", BPATH, num);
if(!(fd=fopen(fname,"rb")))
{
printf("Can't open file: %s\n\n",fname);
exit(0);
}
printf("Reading input file:\n");
printf("%p: %s\n", fd, fname); // prints successfully
fread(&nbins, sizeof(int), 1, fd);
printf("nbins = %d", nbins); // seg faults before this print
/* EDIT: the above print isn't properly flushed without an \n
* The seg fault was not caused by the fread(), but the lack of
* the above print lead to the confusion */
coords = malloc(nbins * sizeof(float));
fread(coords, sizeof(float), nbins, fd);
fclose(fd);
free(coords);
return(0);
}
文件是使用以下格式创建的:
int nbins[1];
nbins[0] = 5; // this 5 is just an example...
fwrite(nbins, sizeof(int), 1, file_ptr);
fwrite(coords, sizeof(float), nbins[0], file_ptr);
我也试过使用:
int *nbins = malloc(sizeof(int));
fread(nbins, sizeof(int), 1, fd);
但这并没有解决问题。
该文件确实存在并且可读;我可以使用 Python 和 NumPy 的 fromfile()
很好地阅读它。我错过了一些明显的东西吗?谢谢!
您可能 undefined behavior,具有以下情况:
int nbins;
没有初始化 nbins
,所以它包含垃圾数据,可能是一个非常大的数字。
fread(&nbins, sizeof(int), 1, fd);
未经过测试,因此可能会失败并保持 nbins
未初始化。阅读 fread。
printf("nbins = %d", nbins);
没有 \n
并且后面没有明确的 fflush
所以不要显示任何东西(因为 stdout
是 通常行缓冲)。
coords = malloc(nbins * sizeof(float));
会请求大量内存,因此会失败并在 coords
中获取 NULL
fread(coords, sizeof(float), nbins, fd);
写入 NULL
指针,给出分段违规,因为 UB
你很幸运。事情可能 worse (we all could be annihilated by a black hole). You could also experiment some nasal demons,甚至更糟,有一些 似乎 显然有效的执行。
下次,请避开UB。我不想消失在黑洞里,所以请耐心等待。
顺便说一句,如果你使用 GCC, compile with all warnings and debug info : gcc -Wall -Wextra -g
. It would have warned you. And if it did not, you'll get the SEGV under the gdb
debugger. On Linux both valgrind and strace 也会有所帮助。
请注意,无用的初始化(例如 explicit int nbins = 0;
在您的情况下)在实践中不会造成伤害。如果它们无用(并且当它们并非无用时,如您的情况,它们非常快),优化编译器可能会删除它们。
必读
拉特纳的博客:What Every C Programmer should know about UB. Related notion: the As-if rule。
另请阅读您正在使用的每个函数的文档(甚至与printf
一样常见)。
似乎有大约 10 个问题和(大部分)成功的答案解决了 C 中错误使用 fread() 导致的分段错误。也就是说,我遇到了这样的问题,但还没有找到解决方案。
我有一个二进制文件,其中包含一个 int
(称之为 nbins)和一个 float
数组(大小为 nbins)。当我尝试读取此文件时,它成功打开并指向文件句柄,但在读取 nbins int
时出现分段错误。这是一个最小的例子:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BPATH "/path/to/file"
int main(int agrc, char **argv)
{
FILE *fd;
int num;
char fname[500]={};
int nbins;
float *coords;
num = 5;
sprintf(fname,"%s/file%d.dat", BPATH, num);
if(!(fd=fopen(fname,"rb")))
{
printf("Can't open file: %s\n\n",fname);
exit(0);
}
printf("Reading input file:\n");
printf("%p: %s\n", fd, fname); // prints successfully
fread(&nbins, sizeof(int), 1, fd);
printf("nbins = %d", nbins); // seg faults before this print
/* EDIT: the above print isn't properly flushed without an \n
* The seg fault was not caused by the fread(), but the lack of
* the above print lead to the confusion */
coords = malloc(nbins * sizeof(float));
fread(coords, sizeof(float), nbins, fd);
fclose(fd);
free(coords);
return(0);
}
文件是使用以下格式创建的:
int nbins[1];
nbins[0] = 5; // this 5 is just an example...
fwrite(nbins, sizeof(int), 1, file_ptr);
fwrite(coords, sizeof(float), nbins[0], file_ptr);
我也试过使用:
int *nbins = malloc(sizeof(int));
fread(nbins, sizeof(int), 1, fd);
但这并没有解决问题。
该文件确实存在并且可读;我可以使用 Python 和 NumPy 的 fromfile()
很好地阅读它。我错过了一些明显的东西吗?谢谢!
您可能 undefined behavior,具有以下情况:
int nbins;
没有初始化nbins
,所以它包含垃圾数据,可能是一个非常大的数字。fread(&nbins, sizeof(int), 1, fd);
未经过测试,因此可能会失败并保持nbins
未初始化。阅读 fread。printf("nbins = %d", nbins);
没有\n
并且后面没有明确的fflush
所以不要显示任何东西(因为stdout
是 通常行缓冲)。coords = malloc(nbins * sizeof(float));
会请求大量内存,因此会失败并在coords
中获取 fread(coords, sizeof(float), nbins, fd);
写入NULL
指针,给出分段违规,因为 UB
NULL
你很幸运。事情可能 worse (we all could be annihilated by a black hole). You could also experiment some nasal demons,甚至更糟,有一些 似乎 显然有效的执行。
下次,请避开UB。我不想消失在黑洞里,所以请耐心等待。
顺便说一句,如果你使用 GCC, compile with all warnings and debug info : gcc -Wall -Wextra -g
. It would have warned you. And if it did not, you'll get the SEGV under the gdb
debugger. On Linux both valgrind and strace 也会有所帮助。
请注意,无用的初始化(例如 explicit int nbins = 0;
在您的情况下)在实践中不会造成伤害。如果它们无用(并且当它们并非无用时,如您的情况,它们非常快),优化编译器可能会删除它们。
必读
拉特纳的博客:What Every C Programmer should know about UB. Related notion: the As-if rule。
另请阅读您正在使用的每个函数的文档(甚至与printf
一样常见)。