我使用 fread 在 BMP 上读取分段错误信息头。请问我该如何解决?
Posted
技术标签:
【中文标题】我使用 fread 在 BMP 上读取分段错误信息头。请问我该如何解决?【英文标题】:I get segmentation fault reading infoheader on a BMP using fread. How do I fix this please? 【发布时间】:2011-09-14 08:34:52 【问题描述】:这让我很困惑,我该如何解决这个问题?我知道我没有错误检查,但我猜它们不是必需的,因为它仅限于我的桌面。它显然不能是EOF。它用于 infoheader 结构,fileheader 工作正常。我需要换一条新线路吗?
#include <stdio.h>
#include <stdlib.h>
typedef struct
unsigned char fileMarker1; /* 'B' */
unsigned char fileMarker2; /* 'M' */
unsigned int bfSize;
unsigned short unused1;
unsigned short unused2;
unsigned int imageDataOffset; /* Offset to the start of image data */
FILEHEADER;
typedef struct
unsigned int biSize;
int width; /* Width of the image */
int height; /* Height of the image */
unsigned short planes;
unsigned short bitPix;
unsigned int biCompression;
unsigned int biSizeImage;
int biXPelsPerMeter;
int biYPelsPerMeter;
unsigned int biClrUsed;
unsigned int biClrImportant;
INFOHEADER;
typedef struct
unsigned char b; /* Blue value */
unsigned char g; /* Green value */
unsigned char r; /* Red value */
IMAGECOMPONENT;
int fileheadfunc(FILE *image);
int infoheadfunc(FILE *image);
int main( int argc, char *argv[] )
char *filename; /* *threshholdInput = argv[2]; */
FILE *image;
int filehead, infohead;
filename = argv[1];
/* int threshhold = atoi(threshholdInput); */
if (argc != 2)
printf(" Incorrect Number Of Command Line Arguments\n");
return(0);
image = fopen( filename, "r");
if (image == NULL)
fprintf(stderr, "Error, cannot find file %s\n", filename);
exit(1);
filehead = fileheadfunc(image);
infohead = infoheadfunc(image);
fclose(image);
return(0);
int fileheadfunc(FILE *image)
FILEHEADER *header;
long pos;
fseek (image , 0 , SEEK_SET);
fread( (unsigned char*)header, sizeof(FILEHEADER), 1, image );
if ( (*header).fileMarker1 != 'B' || (*header).fileMarker2 != 'M' )
fprintf(stderr, "Incorrect file format");
exit(1);
printf("This is a bitmap!\n");
pos = ftell(image);
printf("%ld\n", pos);
printf("%zu\n", sizeof(FILEHEADER));
return(0);
int infoheadfunc(FILE *image)
INFOHEADER *iheader;
fseek (image, 0, SEEK_CUR );
fread( (unsigned int*)iheader, sizeof(INFOHEADER), 1, image );
printf("Width: %i\n", (*iheader).width);
printf("Height: %i\n", (*iheader).height);
return(0);
【问题讨论】:
【参考方案1】:您实际上并没有为 BMP 标头数据结构分配任何存储空间,例如你需要改变这个:
int fileheadfunc(FILE *image)
FILEHEADER *header;
long pos;
fseek(image, 0, SEEK_SET);
fread((unsigned char*)header, sizeof(FILEHEADER), 1, image);
...
到这里:
int fileheadfunc(FILE *image)
FILEHEADER header; // <<<
long pos;
fseek(image, 0, SEEK_SET);
fread(&header, sizeof(FILEHEADER), 1, image); // <<<
...
此外,正如前面在上面的 cmets 中所指出的,在定义结构之前需要 #pragma pack(1)
(或等效项,如果您不使用 gcc 或 gcc 兼容的编译器)以消除不需要的填充。 (注意:在结构定义之后使用#pragma pack()
来恢复正常的结构填充/对齐。)
【讨论】:
干杯!我可以使用指针,我可以使用结构,我可以使用 fread,但是把它们粘在一起我就迷路了。 :) @Connie:登录镜头,但是您使用的是什么平台?请注意,所有 BMP 标头字段都是小端序,因此如果您使用 PowerPC 之类的大端序,则需要进行一些字节交换。否则,如果您仍然卡住,那么我建议您使用最新代码发布一个新问题。【参考方案2】:代码有两个问题:
对齐
出于性能原因,除非另有指示,否则编译器会将结构字段安排在其“自然边界”上,从而有效地在字节大小字段之间留下未初始化的间隙。添加
#pragma pack(1)
在结构定义之前,你应该没问题。它也很容易测试:只需在没有和使用 pragma pack 的情况下打印出结构大小,您就会看到差异。
分配
正如 Paul R 已经说过的,您应该为标题分配空间,而不仅仅是提供指向结构的指针。 fileheadfunc 工作的事实是一个巧合,当数据写入分配的空间之外时,没有任何东西被破坏。
最后一个,只是为了预防起见:如果你想将读取的结构返回给调用程序,不要只返回一个指向函数中分配的结构的指针,因为这会导致类似于你未分配的变量的问题现在有。在调用函数中分配它们,并将指向该变量的指针传递给标头读取函数。
编辑关于最后一点的说明:
不要
FILEHEADER * fileheadfunc(FILE *image)
FILEHEADER header;
...
return &header; // returns an address on the function stack that will
// disappear once you return
做
int fileheadfunc(FILE *image, FILEHEADER *header)
...
会这样调用
...
FILEHEADER header;
returnvalue = fileheaderfunc(imagefile,&header);
EDIT2:刚刚注意到您阅读DIB header 的方式不正确。该标头有几种变体,具有不同的大小。因此,在读取文件头后,您首先需要将 4 个字节读入一个无符号整数,并根据读取的值选择要使用的正确 DIB 头结构(不要忘记您已经读取了它的第一个字段!)或告诉用户您遇到不受支持的文件格式。
【讨论】:
我不太清楚你在最后一段中的意思,但这可能只是因为我不需要暗示它,所以我实际上看不到它,但我会记在心上。谢谢。 :) 你的解释很好。 哦,是的,那个。我的讲师对此非常着迷。 我不能玩这个结构,这是给定的任务。我使用 fileheader1 和 fileheader2 检查适当的文件。感谢您的周到,但这不是必需的。 如果对您有帮助,请问您接受***.com/faq#howtoask 中解释的答案吗?谢谢。以上是关于我使用 fread 在 BMP 上读取分段错误信息头。请问我该如何解决?的主要内容,如果未能解决你的问题,请参考以下文章