内存对齐
内存对齐
转载请注明,谢谢嗷~
引言
前几天笔者在用cpp进行BMP读入的时候,读入总是有问题
结果发现结构体写的并没有问题,二进制读入也没有问题
而是我的内存设定上出了问题,为了说明为什么让我们先看下图
看到这里,你感觉是不是人都傻了,int和char怎么会是8个字节嘞?
经过我一番深入研究,发现这原来是内存对齐产生的问题
强调
内存对齐可能在不同编译器直接存在差异
介绍
虽然所有变量是保存在特定地址的内存中,但是内部很多变量,如类,结构体中的,他们是按照内存对齐的方式储存的
那什么叫对齐嘞?
即通过填充0的方式,来使得存储内容的大小被扩大,成为特定值的某倍
原因有:
1)使得数据读取更加高效
2)不是所有的硬件平台都支持非对齐读入(特别是嵌入式系统中使用的低端处理器)
对齐原则pragma pack(x)
以下语句,设定了读取的最小单位x,以字节为单位
#pragma pack(x)
注意Windows环境下x默认为4字节
我们假设某个结构体中最大数据类型对应的字节数就是y
那么在这个结构体中,决定真正内存填充的基本单位是 MIN(x,y)
那么真正内存大小是MIN(x,y)乘以 填充数N
太抽象?举个栗子吧!
第一个例子,我们在上面的程序仅仅多添加了一句(光标所示位置)
#pragma pack(1)
这就输出了我们心中的理想值
WHY?因为现在我们设置了最小读入单位为1字节,与结构体中最大内存的数据类型long long int比较,它依然是小者,所以当前填充的最小单位是1字节,这也就有了我们想要的结果
再看下面这个例子:
我们设置当前最小读入单位为2字节,同样比较于结构体中最大者,它依然小,所以当前内存填充字节数为2
结构体A好理解,那么B,C嘞?我们可以再看下图来直观感受一下
结构体是顺序储存,结构体B与C他们虽然都有两个字符型,但是由于内存填充最小单位的设定,最终使得他们的内存不一样
BMP读入的问题
现在再让我们看看BMP图像读入过程中,产生的问题吧
这是BMP(标准位图格式)文件头部分
注意这里设置是内存填充字节是默认的4字节
很明显,我们看到这个结构体,它里面即有unsigned int型,也有unsigned short型
那么问题就产生了,它读入就很容易读错,
并且两个short连着了一起,不表现出填充带来的异状
真正让这个文件出错的是
WORD bfType;
这个是短整型,再未加声明的情况下,莫名其妙被填充成4字节了,这也就使得该结构体成为了16字节,而非我们期望的14字节
这也就间接导致BMP的内容被我们过多地读入了,使得后面的内容前移
这会导致什么?像我这个例子,本来位图比较小的宽高被存成两个巨大无比的数,虽说这对24位后面每个像素的RGB读入影响不大,图像也处理成功了,但是内存溢出了并异常退出
那倘若下次宽高存的是别的值嘞?