结构体的字节对齐是我很早就想全面了解一下的东西,这个东西本质上是和硬件相关的,本来要想真正全面了解的话必须得知道CPU的结构、内存的结构、CPU指令是如何执行的等这些硬件层的东西才行,并不是说了解几个寄存器写两句汇编码就可以的,和这个没联系。在尝试了几次之后,迫于个人能力问题,无奈之下只好放弃深层次的了解,只能了解一下字节对齐的规则,至于为什么要对齐的话题,大概也就只能从网络上那几句肤浅的话了解到了:
“一些平台对某些特定类型的数据只能从某些特定地址开始存 ……最常见的是如果不按照适合其平台要求对 数据存放进行对齐,会在存取效率上带来损失……”
只是想了解字节对齐的规则也不是想象中那么容易的事情,对齐规则本身并不算复杂,而最困惑的是网上各种错误的文章,至少我看过的那几十篇包括一些重复的转载和引用,基本上是错的。当然,也并不是说他们错得多么的离谱,大致还是对的,只是一些困惑的地方从来没有人去证实,都自然而然的想当然了,而结果却是错误的。
所以我还是那句话,从来都不带怀疑和思考的精神去看别人的东西,从来不经过自己的证实就轻易相信,那么,误导了你也是你自己活该~~
我写这篇笔记,首先是要证明网上那些错误的地方,以及给出我自己的一些结论。然后就是给出我自己总结出来的一个字节对齐规则的版本。
1. 证明它是错的
我所说的他们那些错误的地方,基本上可以归结于一个问题上的错误,那就是对变量的起始地址的假设。
很多文章大概都有像这样的结论:
1. 数据项只能存储在地址是数据项大小的整数倍的内存位置上;
2. 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
3. 对齐在N上,也就是说该数据的"存放起始地址%N=0
很明显,如果对数据存放地址的把握错误了的话,那么由此推断出来的地址对齐规则也就全都是错的了,而事实上也是如此。我研究这个课题 80%的时间都是花在这个上面,而真正的对齐规则一个下午应该就可以解决了。
当然,像上面的结论在一般情况下基本上是正确的,也就是说:
char变量的地址 %1 =0;
short变量地址 %2 =0;
int变量的地址 %4 =0;
double变量的地址 %8 =0
这里假设:
sizeof(char) = 1;
sizeof(short) = 2;
sizeof(int)=4;
sizeof(double)=8
这是 win32 平台上的实际值,此篇都以此假设为基础。
当这些变量是处于内存的数据区(或只读数据区)或者是从堆上分配出来的话,应该都是正确的,因为编译器和堆管理可能会帮你把这件事情做得很好,而程序员在代码里面基本上控制不了这些区域的变量的起始地址,实则我的多次实际测试也都符合上面的结论,即变量存放起始地址%N=0,结构体也符合首