Reputation: 302
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.
Upvotes: 0
Views: 1855
Reputation: 1139
If you want it to work, even consider that is not correct to read the entire struct, you should be very careful when defining your struct to have absolutely control of the pads.
your struct should look something like this (if you have a 32bit platform).
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.
...
}
and later you need to manipulate the data to get the correct values.
But remember, this is platform dependent, and usually do not worth the pain.
Upvotes: 0
Reputation: 238
The problem is in your struct BMP, why not use ready definition, e.g. the one in 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)
Upvotes: 2
Reputation: 2351
That is because the structure was padded. This means that the size of the structure will not be equal to the sum of the sizes of every individual element of the structure. This is done to align the bytes to improve performance.
Section 6.2.6.1 of the C11 standard says:
When a value is stored in an object of structure or union type, including in a member object, the bytes of the object representation that correspond to any padding bytes take unspecified values.
In short, the padding of a structure is unspecified behaviour. This means any implementation can do whatever it wants without documenting it.
Upvotes: 1
Reputation: 400129
Probably because of internal padding in the structure, the original attempt is a very bad and unsafe way of doing binary I/O with a struct.
It's best to load the well-known number of bytes into a byte buffer, then decode each field and copying it to the structure in memory.
Also note that you shouldn't cast the return value of malloc()
in C.
Upvotes: 3