内存对齐的问题!

Csuxiaowu 2010-08-12 10:53:03
#include <stdio.h>
//using namespace std;
struct foo
{
//short s; //c1 00000002,s 00000000,c2 00000003,i 00000004
char c1;
//short s; //c1 00000000,s 00000002,c2 00000004,i 00000008
char c2;
//short s; //c1 00000000,s 00000002,c2 00000001,i 00000004
int i;
short s; //c1 00000000,s 00000008,c2 00000001,i 00000004
};

/*
这个程序运行在VC6.0下:
对于第1、3、4这三种情况来讲,我的理解是以4字节为单位对齐,
这样的结果都好理解,
可是第2种情况,实在不明白,各位帮解说下,
还有就是内存以多少字节为单位对齐,是CPU的事情,还是编译器的事情?
好像VC里面工程设置里面C/C++选项里面有个struct member alignment
但是我改变设置,输出也不改变。
*/
int main()
{
struct foo a;
printf("c1 %p, s %p, c2 %p, i %p\n",
(unsigned int)(void*)&a.c1 - (unsigned int)(void*)&a,
(unsigned int)(void*)&a.s - (unsigned int)(void*)&a,
(unsigned int)(void*)&a.c2 - (unsigned int)(void*)&a,
(unsigned int)(void*)&a.i - (unsigned int)(void*)&a);
printf("%d\n",sizeof(a));

return 0;
}
...全文
125 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
libinfei8848 2010-08-13
  • 打赏
  • 举报
回复
编译器会进行优化的,关闭优化再看看结果
Erorr 2010-08-13
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 csuxiaowu 的回复:]

引用 10 楼 erorr 的回复:
从逻辑上分析,CPU不需要对C语言负责,因为CPU远远早于C语言
但C语言要对CPU以及系统总线负责,因为这样可以充分利用硬件特性
所以肯定是编译器的事情
字节对齐的原则之一就是一个变量不能跨越4倍地址,当然double只能跨越一次,所以第二种情况的int只能在0008那里

当我点击了结贴的时候,刷新了一下 又有两位朋友的回复了,
字节对齐的……
[/Quote]
我说话一般语无伦次的
其实还是总线的问题,32位机器上,寄存器也都是32位的,double占了64个bit,所以肯定要取址两次,而其他32位数据要保证一次取址操作就能把值取出来
例如0000,0004这样的地方取值效率比较高,如果某个int变量从XXXX0002开始,经过0003、0004、0006,那么数据总线需要取两次值。另外还需要重新组织数据
lazy_2010 2010-08-12
  • 打赏
  • 举报
回复
所谓跨越,应该是说,假如一个 int,变量地址尽量在一个 [xxx0, xxx1, xxx2, xxx3] 之内,
而不要占用 [xxx1, xxx2, xxx3, xxx4] 这四个字节;(跨越了 xxx4,地址是 4 的倍数)

当然由于 double 是 8 个字节,必然会跨越 1 个 xxx0, xxx4, xxx8 或者 xxxb
Csuxiaowu 2010-08-12
  • 打赏
  • 举报
回复
----如果一个变量在这里开始
----
----
----
----那么下一个变量不会越过这个位置,除非它是double?
----
georgy0910 2010-08-12
  • 打赏
  • 举报
回复
路过,学习
lazy_2010 2010-08-12
  • 打赏
  • 举报
回复
double 是 8 字节的;在 win32 下,寄存器是 32 位的,4 字节。
Csuxiaowu 2010-08-12
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 erorr 的回复:]
从逻辑上分析,CPU不需要对C语言负责,因为CPU远远早于C语言
但C语言要对CPU以及系统总线负责,因为这样可以充分利用硬件特性
所以肯定是编译器的事情
字节对齐的原则之一就是一个变量不能跨越4倍地址,当然double只能跨越一次,所以第二种情况的int只能在0008那里
[/Quote]
当我点击了结贴的时候,刷新了一下 又有两位朋友的回复了,
字节对齐的原则之一就是一个变量不能跨越4倍地址,当然double只能跨越一次
这句不太理解啊 请讲解一下 多谢
Erorr 2010-08-12
  • 打赏
  • 举报
回复
从逻辑上分析,CPU不需要对C语言负责,因为CPU远远早于C语言
但C语言要对CPU以及系统总线负责,因为这样可以充分利用硬件特性
所以肯定是编译器的事情
字节对齐的原则之一就是一个变量不能跨越4倍地址,当然double只能跨越一次,所以第二种情况的int只能在0008那里
cattycat 2010-08-12
  • 打赏
  • 举报
回复
4字节对齐,c1和c2是靠在一起的,然后后面空两个字节,i是在第5个字节,s是第9个字节,地址从0开始的话,c1 0,c2 1, i 4,s 8.
对齐是编译器设定的。如果不对齐,紧凑方式,用
#pragma pack(push, 1)
struct
{ ...
};
#pragma pack(pop)
Csuxiaowu 2010-08-12
  • 打赏
  • 举报
回复
感谢楼上的各位朋友,明白了,
brookmill 2010-08-12
  • 打赏
  • 举报
回复
brookmill 2010-08-12
  • 打赏
  • 举报
回复
short本身的大小是2字节,所以默认要求2字节对齐。
类似的,int默认要求4字节对齐,double默认要求8字节对齐。
楼主可以试试在你的结构里再加个double进去看看
slhkzyl 2010-08-12
  • 打赏
  • 举报
回复
我之前也遇到这个问题l
参照网上和自己一些思考做如下解释:
一般来说,在结构体中的对齐是以数据类型宽度最大的那个对齐,所以对char short int 就是以4字节对齐补齐,而对于有double类型等,也是以4字节对齐,我了解是:这个一般机子是32位有关。

对于你上述的第二种情况:计算机系统对基本类型数据在内存中存放的位置有限制的缘故,可能(我只是猜测):对char地址需被1整除,存short地址能够被2整除,-----,依这种结论,当你结构体第一个是char占空间为0x000000,因为第二个元素是short,存放他的地址需能被2整除,故有c1*s c1*** i(*表示补齐位)

( ⊙o⊙ )哇,LZ分全给我吧
Csuxiaowu 2010-08-12
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 brookmill 的回复:]
第2种情况也不难理解呀,short是2字节对齐的。
c1在0,s如果在1就不对齐了,如果放到4是不必要的浪费,于是就放在2,然后把c2挤到4去了。
[/Quote]
为何1就不对齐了?
地址为什么要是偶数位开始?
lazy_2010 2010-08-12
  • 打赏
  • 举报
回复
补充一下,如果你改变编译设置却不管用,建议你关闭开发工具,重新打开,检查设置,然后 rebuild all 一次;

或者,在代码中指定(VC/VS)

#pragma pack(push, 1)
struct ...
#pragma pack(pop)

大体是这样的语句,如果不行,你可能需要查一下 MSDN 了。
brookmill 2010-08-12
  • 打赏
  • 举报
回复
字节对齐是编译器决定的,可以通过pragma pack 等方法来设置
brookmill 2010-08-12
  • 打赏
  • 举报
回复
第2种情况也不难理解呀,short是2字节对齐的。
c1在0,s如果在1就不对齐了,如果放到4是不必要的浪费,于是就放在2,然后把c2挤到4去了。

lazy_2010 2010-08-12
  • 打赏
  • 举报
回复
我的理解:

字节对齐,是编译器的事情;

对于第二种情况,


struct foo
{
char c1;
short s; //c1 00000000,s 00000002,c2 00000004,i 00000008
char c2;
int i;
};


编译器为了代码的访问快速,实际分配给 c1 两个字节(保留了 c1 后面 1 个字节,代码只能访问一个字节),避免 s 在访问的时候,地址是“奇数”;为了避免 i 的地址不是 4 的整数倍,把 c2 后面的 3 个字节也给保留了。

69,382

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧