我使用 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 上读取分段错误信息头。请问我该如何解决?的主要内容,如果未能解决你的问题,请参考以下文章

Fread 返回 0,从 BMP 文件中读取像素

使用 fread() 函数时出现分段错误

读取 bmp 文件并将数据发送到数组

如何用c语言printf输出bmp图片的像素信息。

C++:使用 fread 和 fwrite 循环复制 bmp,导致输出 bmp 填充输入 bmp 中第一个颜色

如何使用 fread 读取 R 中的 gz 文件?