• [转]关于结构体成员内存对齐的问题


    转载声明: 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

  • 相关阅读:
    stm32之PWM博客好文收藏
    CSDN怎么转载别人的博客
    STM32F103单片机学习—— 通用定时器
    STM32 通用定时器好文章收藏
    stm32基本定时器timer6的原理与使用
    freertos优秀博客收藏
    StretchBlt函数和BitBlt函数的用法
    对话框添加背景图片
    vc 使窗口置顶 在最前面
    CWnd::MoveWindow 详解
  • 原文地址:https://www.cnblogs.com/wqlblogger/p/723737.html
Copyright © 2020-2023  润新知