zoukankan      html  css  js  c++  java
  • [转]关于结构体成员内存对齐的问题

    转载声明: www.eternity3.com.
    首先要明确什么是内存对齐问题。
    假设我们同时声明两个变量:

     程序代码
    char a;
    short b;


    如果我们用&(取地址符号)观察变量a, b的地址的话,我们会发现(以16位CPU为例):
    如果a的地址是0x0000,那么b的地址将会是0x0002或者是0x0004。
    那么就出现这样一个问题:0x0001这个地址没有被使用,那它干什么去了?
    答案就是它确实没被使用。因为CPU每次都是从以2字节(16位CPU)或是4字节(32位CPU)的整数倍的内存地址中读进数据的。
    如果变量b的地址是0x0001的话,那么CPU就需要先从0x0000中读取一个short,取它的高8位放入b的低8位,然后再从0x0002中读取下一个short,取它的低8位放入b的高8位中,如图:


    这样的话,为了获得b的值,CPU需要进行了两次读操作。
    但是如果b的地址为0x0002,如图:


    那么CPU只需一次读操作就可以获得b的值了。
    所以编译器为了优化代码,往往会根据变量的大小,将其指定到合适的位置,即称为内存对齐。

    回到正题,同样的问题也会出现在结构体内部成员变量身上,考虑在32位CPU上处理下面一个结构:

     程序代码
    typedef struct {
        unsigned short   bfType;         // 文件类型
        unsigned long    bfSize;         // 文件大小
        unsigned short   bfReserved1;    // 保留位
        unsigned short   bfReserved2;    // 保留位
        unsigned long    bfOffBits;      // 数据偏移位置
    }BMPFILEHEADER;


    由于32位的CPU是按4字节对齐的,bfType的长度是2字节,bfSize的长度是4字节,这意味着这两个变量的地址将不是连续的,它们之间将会有2字节的空隙。这个就会为fread, fwrite等函数的操作造成困难,导致数据的读写错误,因为我们需要的数据很可能被填充到那个没有使用的空隙里面了。
    所以我们需要指示编译器,让它不要按4字节对齐,如下:

     程序代码
    #pragma pack(2)
    typedef struct {
        unsigned short   bfType;         // 文件类型
        unsigned long    bfSize;         // 文件大小
        unsigned short   bfReserved1;    // 保留位
        unsigned short   bfReserved2;    // 保留位
        unsigned long    bfOffBits;      // 数据偏移位置
    }BMPFILEHEADER;
    #pragma pack()


    其中第一个#pragma pack(2)预处理指令指示编译器,下面的代码所涉及到的变量分别使用2字节对齐,第二个#pragma pack()预处理指令用以恢复编译器的默认对齐宽度。这样便不会出现我们所不希望看到的那些空隙。

    文章转载自【Eternity's Site】http://www.eternity3.com.cn/blog/article.asp?id=152

  • 相关阅读:
    Excel 相对引用与绝对引用
    SQL Update 巧用
    Delphi 多步操作产生错误,请检查每一步的状态值
    cxGrid 增加序号 (非数据库绑定模式) (测试通过)
    delphi cxgrid 使用方法
    如何使满足条件的数据显示不同的颜色
    Delphi中Format与FormatDateTime函数详解
    常用的日期时间函数
    100m和1000m网线的常见制作方法
    基于请求的分布式互斥算法
  • 原文地址:https://www.cnblogs.com/wqlblogger/p/723737.html
Copyright © 2011-2022 走看看