0

I'm trying to read the header of a BMP file and then display it's contents.

struct BMP *bmp;
bmp = (struct BMP*)malloc(sizeof(struct BMP));
    if(bmp)
    {
        fread(bmp,sizeof(struct BMP),1,bmpFile); //This does not work for me

        //Then we display the contents
        printf("#######CABECALHO DE UM ARQUIVO .BMP (BITMAP)#########\n");
        printf("\n");
        printf("Tipo de Arquivo (2 bytes): %c%c\n", bmp->id[0],bmp->id[1]);
        printf("Tamanho do arquivo (4 bytes): %d Kb\n",bmp->filesize/1024);
        printf("Reservado1 (2 bytes): %x\n",bmp->reserved[0]);
        printf("Reservado2 (2 bytes): %x\n",bmp->reserved[1]);
        printf("Tamanho do Cabecalho BMP: %d\n",bmp->headersize);
        printf("Tamanho do Info Header (4 bytes): %d\n", bmp->infosize);
        printf("Largura: (4 bytes): %d\n", bmp->width);
        printf("Altura: (4 bytes): %d\n", bmp->height);
        printf("Plane: (2 bytes): %x\n", bmp->plane);
        printf("Bits por Pixel: (2 bytes): %x\n", bmp->bits);
        printf("Compressao: (4 bytes): %d\n", bmp->compression);
        printf("Tamanho da Imagem: (4 bytes): %d\n", bmp->imagesize/1024);
        printf("X: (4 bytes): %d\n", bmp->x);
        printf("Y: (4 bytes): %d\n", bmp->y);
        printf("Nro de Cores : (4 bytes): %d\n", bmp->clrUsed);
        printf("Nro de Cores Importantes : (4 bytes): %d\n", bmp->clrImportant);
        printf("\n");
        printf("#######FIM DO CABECALHO TOTAL DE 50 BYTES#########");
   }

However the only accurate information it shows me is the first 2 bytes all the other values are incorrect.

If instead of reading the whole struct

struct fread(bmp,sizeof(struct BMP),1,bmpFile);

I read each element at a time

        fread(&bmp->id[0],sizeof(char),1,bmpFile);
        fread(&bmp->id[1],sizeof(char),1,bmpFile);
        fread(&bmp->filesize,sizeof(int),1,bmpFile);
        fread(&bmp->reserved[0],sizeof(short),1,bmpFile);
        fread(&bmp->reserved[1],sizeof(short),1,bmpFile);
        fread(&bmp->headersize,sizeof(int),1,bmpFile);
        fread(&bmp->infosize,sizeof(int),1,bmpFile);
        fread(&bmp->width,sizeof(int),1,bmpFile);
        fread(&bmp->height,sizeof(int),1,bmpFile);
        fread(&bmp->plane,sizeof(short),1,bmpFile);
        fread(&bmp->bits,sizeof(short),1,bmpFile);
        fread(&bmp->compression,sizeof(int),1,bmpFile);
        fread(&bmp->imagesize,sizeof(int),1,bmpFile);
        fread(&bmp->x,sizeof(int),1,bmpFile);
        fread(&bmp->y,sizeof(int),1,bmpFile);
        fread(&bmp->clrUsed,sizeof(int),1,bmpFile);
        fread(&bmp->clrImportant,sizeof(int),1,bmpFile);

then all values are displayed correctly... So my question is why is that happening what is different when I read the whole struct at once.

4

4 回答 4

3

可能是由于结构中的内部填充,最初的尝试是使用结构进行二进制 I/O 的一种非常糟糕且不安全的方式。

最好将众所周知的字节数加载到字节缓冲区中,然后解码每个字段并将其复制到内存中的结构中。

另请注意,您不应强制转换malloc()in C的返回值。

于 2013-04-24T13:11:44.653 回答
2

问题出在您的 struct BMP 中,为什么不使用现成的定义,例如 WinGDI.h 中的定义

#pragma pack(push,1)
typedef struct tagBITMAPINFOHEADER{
        DWORD      biSize;
        LONG       biWidth;
        LONG       biHeight;
        WORD       biPlanes;
        WORD       biBitCount;
        DWORD      biCompression;
        DWORD      biSizeImage;
        LONG       biXPelsPerMeter;
        LONG       biYPelsPerMeter;
        DWORD      biClrUsed;
        DWORD      biClrImportant;
} BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;
#pragma pack(pop)
于 2013-04-24T13:31:33.320 回答
1

那是因为结构被填充了。这意味着结构的大小将不等于结构中每个单独元素的大小之和。这样做是为了对齐字节以提高性能。

C11 标准的第 6.2.6.1 节说:

当一个值存储在结构或联合类型的对象中时,包括在成员对象中,对应于任何填充字节的对象表示的字节采用未指定的值。

简而言之,结构的填充是未指定的行为。这意味着任何实现都可以在没有文档的情况下做任何它想做的事情。

于 2013-04-24T13:19:14.260 回答
0

如果你想让它工作,即使考虑到阅读整个结构是不正确的,在定义你的结构以完全控制焊盘时,你应该非常小心。

你的结构应该看起来像这样(如果你有一个 32 位平台)。

struct BMP
{
unsigned char id[];
unsigned short filesize_1;  

/* here we need to control the pads to make sure it will fit to our platform.
/ also, the order of msb and lsb may change according to the platform. */

unsigned short filesize_2;  // Now start a new int.
...
}

稍后您需要操作数据以获取正确的值。

但请记住,这取决于平台,通常不值得痛苦。

于 2013-04-24T14:52:17.430 回答