我使用 fread 在 BMP 上读取信息头时出现分段错误。请问我该如何解决这个问题?

发布于 2024-12-05 01:34:49 字数 2691 浏览 0 评论 0原文

这让我陷入了困境,我该如何解决这个问题?我知道我没有错误检查,但我猜它们不是必需的,因为它仅限于我的桌面。显然不可能是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);
}

This is got me pretty stuck, how do I fix this? I know I haven't got error checking, but they aren't required i'd guess since it's restricted to my desktop. It obveously can't be EOF. It's for the infoheader struct, fileheader works fine. Do i need to take a new line or something?

#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);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

孤千羽 2024-12-12 01:34:49

您实际上并没有为 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); // <<<

    ...

另外,如上面评论之一所述,您需要 #pragma pack(1) (或者等效的,如果您不使用 gcc 或 gcc 兼容的编译器)在结构定义之前,以消除不需要的填充。 (注意:在结构定义后使用 #pragma pack() 来恢复正常的结构填充/对齐。)

You're not actually allocating any storage for the BMP header data structures, e.g. you need to change this:

int fileheadfunc(FILE *image)
{
    FILEHEADER *header;
    long pos;

    fseek(image, 0, SEEK_SET);

    fread((unsigned char*)header, sizeof(FILEHEADER), 1, image);

    ...

to this:

int fileheadfunc(FILE *image)
{
    FILEHEADER header; // <<<
    long pos;

    fseek(image, 0, SEEK_SET);

    fread(&header, sizeof(FILEHEADER), 1, image); // <<<

    ...

Also, as previously noted in one of the comments above, you need #pragma pack(1) (or equivalent if you're not using gcc or a gcc-compatible compiler) prior to your struct definitions to eliminate unwanted padding. (NB: use #pragma pack() after your struct definitions to restore normal struct padding/alignment.)

撩人痒 2024-12-12 01:34:49

该代码存在两个问题:

对齐

出于性能原因,除非另有指示,否则编译器将在其“自然边界”上排列结构字段,从而有效地在字节大小字段之间留下未初始化的间隙。 在结构定义之前添加

#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 标头 不正确。该标头有多种变体,具有不同的大小。因此,在读取文件头后,您首先需要将 4 个字节读入一个 unsigned int 中,并根据读取的值选择要使用的正确 DIB 头结构(不要忘记您已经读取了它的第一个字段!)或告诉您遇到的用户不受支持的文件格式。

There are two problems with the code:

Alignment

For performance reasons the compiler will, unless instructed to do otherwise, arrange struct fields on its "natural boundaries", effectively leaving uninitialised gaps between byte-size fields. Add

#pragma pack(1) 

before the struct definitions and you should be fine. It's also easy to test: just print out the struct size without and with pragma pack in place, and you'll see the difference.

Allocation

As Paul R already said, you should allocate space for the headers, not just provide a pointer to the structures. The fact that fileheadfunc works is a coincidence, there just wasn't anything in the way that got smashed when data got written outside of the allocated space.

A last one, just for prevention sake: should you ever want to return the read structures to the calling program, do not just return a pointer to the structure allocated in the function as that will cause problems similat to the unallocated variables you have now. Allocate them in the calling function, and pass a pointer to that variable to the header read functions.

EDIT clarification regarding the last point:

DON'T

FILEHEADER * fileheadfunc(FILE *image)
{
    FILEHEADER header;
    ...
    return &header; // returns an address on the function stack that will 
                    // disappear once you return
}

DO

int fileheadfunc(FILE *image, FILEHEADER *header)
{
    ...
}

which will be called like this

...
FILEHEADER header;
returnvalue = fileheaderfunc(imagefile,&header);

EDIT2: just noticed that the way you read the DIB header is not correct. There are several variations of that header, with different sizes. So after reading the file header you first need to read 4 bytes into an unsigned int and based on the value read select the correct DIB header structure to use (don't forget you already read its first field!) or tell the user you encountered an unsupported file format.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文