这让我很卡住,我该如何解决这个问题?我知道我没有错误检查,但我猜它们不是必需的,因为它仅限于我的桌面。它显然不可能是EOF。它适用于信息标题结构,文件头工作正常。我需要换一条新线吗?
#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 Argumentsn");
return(0);
}
image = fopen( filename, "r");
if (image == NULL)
{
fprintf(stderr, "Error, cannot find file %sn", 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("%ldn", pos);
printf("%zun", 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: %in", (*iheader).width);
printf("Height: %in", (*iheader).height);
return(0);
}
您实际上并没有为 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()
来恢复正常的结构填充/对齐方式。
代码有两个问题:
对准
出于性能原因,编译器将在其"自然边界"上排列结构字段,从而有效地在字节大小字段之间留下未初始化的间隙。 加
#pragma pack(1)
在结构定义之前,你应该没问题。 它也很容易测试:只需打印出结构大小,没有和编译指示包,你就会看到差异。
分配
正如 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);
编辑2:刚刚注意到您读取DIB标头的方式不正确。 该标头有多种变体,大小不同。 因此,在读取文件头后,您首先需要将 4 个字节读取到无符号的 int 中,并根据读取的值选择要使用的正确 DIB 标头结构(不要忘记您已经阅读了它的第一个字段!(或告诉用户您遇到了不受支持的文件格式。