易码技术论坛

 找回密码
 加入易码
搜索
查看: 268003|回复: 4

关于结构体成员内存对齐的问题

[复制链接]
发表于 2006-11-28 12:24:23 | 显示全部楼层
坐个沙发先。慢慢看……
发表于 2006-11-28 13:23:28 | 显示全部楼层
不对齐的数据访问要比对齐的慢,尤其是在risc CPU上
发表于 2006-11-28 15:25:41 | 显示全部楼层
看了下还是不明白,到底是意味着要每次都人工对齐还是已经帮我们对齐了,地址要改啊?
 楼主| 发表于 2006-11-28 18:32:20 | 显示全部楼层
引用第3楼信志2006-11-28 15:25发表的“”:
看了下还是不明白,到底是意味着要每次都人工对齐还是已经帮我们对齐了,地址要改啊?
编译器会为我们对齐,必要时我们需要手动制定编译器的对齐方式
 楼主| 发表于 2006-11-28 12:18:40 | 显示全部楼层 |阅读模式
最近读取BMP文件的时候总有问题,对照了自己和wingdi.h里面的定义的BITMAPFILEHEADER结构,都是一样的,不过就是不能正常读取,最后终于发现是内存对齐问题。总结一篇,供大家分享。

首先要明确什么是内存对齐问题。
假设我们同时声明两个变量:
  1. char a;
  2. 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上处理下面一个结构:
  1. typedef struct {
  2.    unsigned short   bfType;      // 文件类型
  3.    unsigned long   bfSize;      // 文件大小
  4.    unsigned short   bfReserved1;   // 保留位
  5.    unsigned short   bfReserved2;   // 保留位
  6.    unsigned long   bfOffBits;   // 数据偏移位置
  7. }BMPFILEHEADER;
复制代码
由于32位的CPU是按4字节对齐的,bfType的长度是2字节,bfSize的长度是4字节,这意味着这两个变量的地址将不是连续的,它们之间将会有2字节的空隙。这个就会为fread, fwrite等函数的操作造成困难,导致数据的读写错误,因为我们需要的数据很可能被填充到那个没有使用的空隙里面了。
所以我们需要指示编译器,让它不要按4字节对齐,如下:
  1. #pragma pack(2)
  2. typedef struct {
  3.    unsigned short   bfType;      // 文件类型
  4.    unsigned long   bfSize;      // 文件大小
  5.    unsigned short   bfReserved1;   // 保留位
  6.    unsigned short   bfReserved2;   // 保留位
  7.    unsigned long   bfOffBits;   // 数据偏移位置
  8. }BMPFILEHEADER;
  9. #pragma pack()
复制代码
其中第一个#pragma pack(2)预处理指令指示编译器,下面的代码所涉及到的变量分别使用2字节对齐,第二个#pragma pack()预处理指令用以恢复编译器的默认对齐宽度。这样便不会出现我们所不希望看到的那些空隙。
您需要登录后才可以回帖 登录 | 加入易码

本版积分规则

Archiver|手机版|小黑屋|EMAX Studio

GMT+8, 2024-4-20 12:19 , Processed in 0.014194 second(s), 18 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表