读书人

关于内存对齐的,该怎么解决

发布时间: 2012-05-01 12:48:58 作者: rapoo

关于内存对齐的

C/C++ code
#include<stdio.h>struct s1{    char c1;    char c2;    int i;    };struct s2{    char c1;    int i;    char c2;    };void main(){    printf("%d\n%d\n",sizeof(s1),sizeof(s2));}


s1是8字节,s2是12字节,为什么会这样呢?
编译器是vc2010

[解决办法]
默认4字节对齐
S1:1+1+2(补齐)+4=8
S2:1+3(补齐)+4+1+3(补齐)=12
[解决办法]
VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)

提醒:
“学习用汇编语言写程序”

“VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)”
不是一回事!

不要迷信书、考题、老师、回帖;
要迷信CPU、编译器、调试器、运行结果。
并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。
任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实!

[解决办法]
对齐是根据变量的起始地址。
比如 32位机 int 为4字节,则int 的起始地址应该为4的倍数,不够则补齐

如 s1 ,
char c1; //偏移量0(前面没有),为sizeof(char c1)=1的倍数,不用处理
char c2; //偏移量1(前面有一个char),为sizeof(char c2)=1的倍数,不用处理
int i; //偏移量2(前面有两个char),不是sizeof(int i)=4的倍数,于是补2

于是 sizeof(struct s1)=1+1+2(补)+4 = 8

推理 s2,
char c1;//偏移量0(前面没有),为sizeof(char c1)=1的倍数,不用处理
int i; //偏移量1(前面有1个char),不是sizeof(int i)=4的倍数,于是补3
char c2; //偏移量8(前面经过补齐到8了),是sizeof(char c2)=1的倍数,于是不处理
但是,还有一个边界对齐原则,即根据结构中最大的类型做整体对齐,s2中最大的是int =4,
当前是 1+3(补)+4+1=9 不是4的倍数,于是编译器再补3,得到12

还有一个语句
#pragma pack(n) 可以做对齐设定
这个设定会对上述对齐原则有影响,原则是变量类型与n比较,取小者作为对齐标准
最后的边界对齐也是 根据结构中最大的类型与n 相比取小者

推荐一篇文章:
http://hi.baidu.com/wither/blog/item/5ab0adef15311b0dfdfa3cd8.html
[解决办法]
因为你的电脑编译环境是32寻址,还有你的编译器默认设置等原因,所以int型(4字节)必须在能被4字节(32位)整除的地址开始,同样的你所以独立的变量、结构等,都在4字节(32位)地址开始,就是说你的地址开头都是0、4、8、c这样的尾数。用你的两个结构体举个例子:
struct s1
{
0x001c0000: char c1;
0x001c0001: char c2;
0x001c0004: int i;
};
struct s2
{
0x001c0000: char c1;
0x001c0004: int i;
0x001c0008: char c2;
};

这样你再结合一楼对补齐的说明,就可以理解了。
[解决办法]
1、 对于结构的各个成员,第一个成员位于偏移为0的位置,以后每个数据成员的偏移量必须是min(#pragma pack()指定的数,这个数据成员的自身长度) 的倍数。

2、 在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。
[解决办法]
1、 对于结构的各个成员,第一个成员位于偏移为0的位置,以后每个数据成员的偏移量必须是min(#pragma pack()指定的数,这个数据成员的自身长度) 的倍数。

2、 在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。
[解决办法]
CPU对内存的读取不是你想象的那么聪明,楼主可以自行百度内存对齐,关于这个的文章太多了
[解决办法]
#pragma pack(1)
这个宏可以指定字节对齐方式 括号里是1即,1字节对齐
[解决办法]
探讨

VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。
(Linux或Unix下可以在用GDB调试时,看每句C……

[解决办法]
探讨


#pragma pack(1)
这个宏可以指定字节对齐方式 括号里是1即,1字节对齐


[解决办法]
3楼正解。

读书人网 >C++

热点推荐