zoukankan      html  css  js  c++  java
  • 使用标准C读取文件遇到的结构体对齐问题及其解决办法

    作者:朱金灿

    来源:http://blog.csdn.net/clever101

     

             同事使用标准C库读取文件,发现总是读取不对,让我帮忙看一下。

    原来他定义了如下一个结构体:

    // 定义块的结构
    typedef struct {
        unsigned short        id;
        long                len;
    } Chunk3DS; 

           然后这样读取文件:

           if (fread(&chunk,sizeof(Chunk3DS),1,m_fp)!=1)
            {
                return FALSE;
            }

    但是读取的内容总是不对。

            我想到结构体内存对齐这档子事,于是我把读取代码改为:

    Chunk3DS chunk;
    if (fread(&chunk.id,sizeof(unsigned short),1,m_fp)!=1)
            {
                return FALSE;
            }
    if (fread(&chunk.len,sizeof(long),1,m_fp)!=1)
            {
                return FALSE;
            }

          接着我测试了一下:

    int nShortSize = sizeof(unsigned short); // 等于2
    int nLongSize  = sizeof(long); // 等于4
    int SstructSize = sizeof(Chunk3DS); // 等于8

           整整差了两个字节,难怪读取的内容不对。现在我发现由于结构体内存对齐的缘故(结构体内存对齐的原理网上的相关文章很多,在这不进行详述),使用fread接口去读一个结构体的缓冲区常常不准确,其实也不科学,因为文件设计者在设计文件时文件的各个成员肯定都是紧挨着的,因此是使用简单类型逐个去读取。

           如何解决这个问题呢?如前文所述,使用简单类型逐个去读取肯定是可以的,但是如果文件比较复杂的话,这意味着要写比较多的代码。有没有更好的办法呢?也有,可以将结构体做如下定义:

    /* 对齐结构成员到1字节 */
    #ifdef __GNUC__
        #define GNUC_PACKED __attribute__((packed))
    #else
        #define GNUC_PACKED
    #endif
     
    #ifdef __arm 
        #define ARM_PACKED  __packed 
    #else 
        #define ARM_PACKED 
    #endif
     
    #if defined(WIN32) || defined(_WIN64)
        #pragma pack(1)
    #endif
    ARM_PACKED
    typedef struct {
        unsigned short id;
        long len;
    }GNUC_PACKED Chunk3DS;
    #if defined(WIN32) || defined(_WIN64)
        #pragma pack()
    #endif


    参考文献:

    1.  【原创&交流】使用标准C库读文件时需要注意的一个问题

  • 相关阅读:
    stenciljs 学习四 组件装饰器
    stenciljs 学习三 组件生命周期
    stenciljs 学习二 pwa 简单应用开发
    stenciljs ionic 团队开发的方便web 组件框架
    stenciljs 学习一 web 组件开发
    使用npm init快速创建web 应用
    adnanh webhook 框架 hook rule
    adnanh webhook 框架 hook 定义
    adnanh webhook 框架request values 说明
    adnanh webhook 框架execute-command 以及参数传递处理
  • 原文地址:https://www.cnblogs.com/lanzhi/p/6469759.html
Copyright © 2011-2022 走看看