【问题标题】:Reading elements from a struct with fread()使用 fread() 从结构中读取元素
【发布时间】:2013-04-24 13:08:49
【问题描述】:

我正在尝试读取 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);

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

【问题讨论】:

  • 你是用二进制模式打开文件的吗?

标签: c fread


【解决方案1】:

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

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

还要注意你shouldn't cast the return value of malloc() in C

【讨论】:

    【解决方案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)
    

    【讨论】:

    • @Renato,只是一个警告:防止你的结构被填充会降低性能(由于未对齐的内存访问)。
    【解决方案3】:

    那是因为结构被填充了。这意味着结构的大小将不等于结构中每个单独元素的大小之和。这是对align the bytes 进行的,以提高性能。

    C11 standard 的第 6.2.6.1 节说:

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

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

    【讨论】:

      【解决方案4】:

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

      您的结构应该看起来像这样(如果您有 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.
      ...
      }
      

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

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

      【讨论】:

        猜你喜欢
        • 2012-01-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多