使用fread()从结构中读取元素

时间:2013-04-24 13:08:49

标签: c fread

我正在尝试读取BMP文件的标题,然后显示它的内容。

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

然而,它向我显示的唯一准确信息是前2个字节,其他所有值都不正确。

如果不是阅读整个结构

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

我一次读取每个元素

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

然后所有值都正确显示... 所以我的问题是,当我一次读完整个结构时,为什么会发生不同的事情。

4 个答案:

答案 0 :(得分:3)

可能是因为结构中存在内部填充,原始尝试是一种使用结构进行二进制I / O的非常糟糕且不安全的方法。

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

另请注意shouldn't cast the return value of malloc() in C

答案 1 :(得分:2)

问题出在你的结构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)

答案 2 :(得分:1)

那是因为结构是填充的。这意味着结构的大小将不等于结构的每个单独元素的大小的总和。这样做是为了align the bytes以提高效果。

C11 standard的第6.2.6.1节说:

  

当值存储在结构或联合类型的对象中时,包括在成员中   object,对象表示的字节,对应于任何填充字节   未具体的价值观。

简而言之,结构的填充是未指定的行为。这意味着任何实现都可以做任何想做的事情,而无需记录它。

答案 3 :(得分: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.
...
}

以后需要操纵数据才能获得正确的值。

但请记住,这是平台依赖的,通常不值得痛苦。