Merlin

Life was like a box of chocolates. You never know what you're gonna get.

   :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  34 随笔 :: 0 文章 :: 40 评论 :: 0 Trackbacks

老师提出一个很有意思的问题:

class b
{
    
char c1;
    
    
long l;
    
    
char c2;
    
double d;

}
;
class b
{
    
char c1;
    
char c2;

        
long l;
    
    
double d;
    
}
;
在存储的时候用的空间是不一样大的,前者是24,后者是16,为什么?
-------------------------------------------------------------------------------------------------------------------------
我在自己的机器上也运行了,的确如此,我知道16是怎么来的, char是2,long是4,double是8,2+2+4+8=16,而24我就太明白了,说地址是4字节的,char是2,要空两个字节,那第一个也应该是20阿,怎么会是24呢?有明白人的给讲讲!
posted on 2005-11-11 12:56 Merlin 阅读(1997) 评论(15)  编辑 收藏 引用 所属分类: C++

评论

# re: 一个有意思的问题 2005-11-11 13:32 笨笨
你的程序是按照8个字节对齐的
  回复  更多评论
  

# re: 一个有意思的问题 2005-11-11 14:00 nacci
建议你为每个类定义构造函数,然后分别生成对象后,观察每个对象的内存布局。在b中,为了和double d对齐,为c2保留了8 bytes的空间。  回复  更多评论
  

# re: 一个有意思的问题 2005-11-11 16:37 Merlin
为什么就char要对齐阿,而long不用对齐阿?

class b
{
char c1;

long l;

char c2;

long l1;

double d;


};//sizeof(b)=24!
这里面到底是怎么回事啊?  回复  更多评论
  

# re: 一个有意思的问题 2005-11-11 16:56 shootingstars
字节对齐是为了提高从内存中获取变量的效率。
如果数据总线的宽度是32位,那么每次从内存中取数据都是从4的倍数取的。如果不对齐的话,有可能取一个int型数据需要两次操作。

编译器一般都可以使用编译指令来控制是否需要字节对齐。  回复  更多评论
  

# re: 一个有意思的问题 2005-11-11 17:00 笨笨
如果你是VC的话,使用
#pragma pack(push,8)
#pragma pack(1)//使用一个字节对齐
你在这里写代码
#pragma pack(pop,8)

这种情况不能乱用,因为会降低效率
WINDOWS核心编程介绍字节对齐的原因  回复  更多评论
  

# re: 一个有意思的问题 2005-11-11 21:44 Merlin
谢谢了!  回复  更多评论
  

# re: 一个有意思的问题 2005-11-12 12:30 Merlin
当CPU的访问正确对齐的数据时,它的运行效率最高,当数据大小的数据模数的内存地址是0时,数据是对齐的。例如:WORD值应该是总是从被2除尽的地址开始,而DWORD值应该总是从被4除尽的地址开始,数据对齐不是内存结构的一部分,而是CPU结构的一部分。当CPU试图读取的数据值没有正确的对齐时,CPU可以执行两种操作之一:产生一个异常条件;执行多次对齐的内存访问,以便读取完整的未对齐的数据,若多次执行内存访问,应用程序的运行速度就会慢。在最好的情况下,是两倍的时间,有时更长。
-------------《Windows核心编程》
不过我还有一点不明白的:
struct s
{

char a;

long int d;

double c;


};//此时是16
struct s
{

char a;

long int d;

double c;

char a1;


};//而此时是24
也就是说a1用了8个,我觉得就没有道理啊,不是当数据大小的数据模数的内存地址是0时,数据是对齐的么? char没有必要用8个阿!有没有人明白,帮解释一下!  回复  更多评论
  

# re: 一个有意思的问题 2005-11-12 21:21 笨笨
哎,编译器默认是8个行不行呀?  回复  更多评论
  

# re: 一个有意思的问题 2005-11-12 22:49 fireup
编译器默认的对齐是8字节对齐。

两个结构在内存中的分配分别如下图
0 4 8
+-------+-------+
|char |long | 0-7
+-------+-------+
|char | 8-15
+---------------+
|double | 16-23
+---------------+

0 4 8
+-------+-------+
|c|c| |long | 0-7
+-------+-------+
|double | 8-15
+---------------+

  回复  更多评论
  

# re: 一个有意思的问题 2005-11-13 11:10 味全每日C++
还是应该注意这一点 #pragma pack(8)
默认32位是8 ,不排除有的时候让你计算 #pragma pack(4) 的情况..  回复  更多评论
  

# re: 一个有意思的问题 2005-11-27 02:09
学习  回复  更多评论
  

# re: 一个有意思的问题 2005-12-30 10:48
当CPU的访问正确对齐的数据时,它的运行效率最高,当数据大小的数据模数的内存地址是0时,数据是对齐的。例如:WORD值应该是总是从被2除尽的地址开始,而DWORD值应该总是从被4除尽的地址开始,数据对齐不是内存结构的一部分,而是CPU结构的一部分。当CPU试图读取的数据值没有正确的对齐时,CPU可以执行两种操作之一:产生一个异常条件;执行多次对齐的内存访问,以便读取完整的未对齐的数据,若多次执行内存访问,应用程序的运行速度就会慢。在最好的情况下,是两倍的时间,有时更长。
-------------《Windows核心编程》
不过我还有一点不明白的:
struct s
{

char a;

long int d;

double c;


};//此时是16
struct s
{

char a;

long int d;

double c;

char a1;


};//而此时是24
也就是说a1用了8个,我觉得就没有道理啊,不是当数据大小的数据模数的内存地址是0时,数据是对齐的么? char没有必要用8个阿!有没有人明白,帮解释一下!
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

除了结构体内的成员变量要求对齐外,结构自身也是需要对齐的。结构体成员的对齐是用成员本身的大小和#pragma pack(push,n)中的n中较小的数对齐,例如如果成员大小为2,而你指定的对齐方式是4,则该成员按2对齐;结构本身的对其是用结构中最大成员的大小和#pragma pack(push,n)中的n较小的数对齐,例如如果结构中最大成员大小8,而你指定对齐是16,则结构本身按8对齐。

对于
struct s
{

char a;

long int d;

double c;


};//此时是16
编译器默认的一般是8字节对齐。
a大小是1,它就按1字节对齐(因为比指定的8小),存储在0偏移的地方;b大小4,它就按4字节对齐(因为比指定的8小),存在偏移4--7的位置,c大小8,它按8字节对齐,存在偏移8--15的位置。这样3个成员共占用了16字节。由于该结构最大成员c大小为8,所以结构按8字节对齐,16按8园整还是16,因此sizeof s = 16。

而对于
struct s
{

char a;

long int d;

double c;

char a1;


};//而此时是24
前3个成员和上面一样存储,即a在0位置,d在4--7位置,c在8--16位置,但a1按一字节对齐,存在偏移17位置,这样4个成员占用了17字节;整个结构还要按8对齐(因为结构最大成员c大小为8),17按8圆整后是24,因此此时sizeof s = 24。

如果你指定编译器按4字节对齐,即你在开头加上#pragma pack(push,4)
则对于前者为12,后者为16。
我用的是vc7.1。





  回复  更多评论
  

# re: 一个有意思的问题 2005-12-30 11:03
除了结构体内的成员变量要求对齐外,结构自身也是需要对齐的。结构体成员的对齐是用成员本身的大小和#pragma pack(push,n)中的n相比,取较小的数对齐,例如如果成员大小为2,而你指定的对齐方式是4,则该成员按2对齐;结构本身的对其是用结构中所有成员对齐的最大数和#pragma pack(push,n)中的n相比,取较小的数对齐。

对于
struct s
{

char a;

long int d;

double c;


};//此时是16
编译器默认的一般是8字节对齐。
a大小是1,它就按1字节对齐(因为比指定的8小),存储在0偏移的地方;b大小4,它就按4字节对齐(因为比指定的8小),存在偏移4--7的位置,c大小8,它按8字节对齐,存在偏移8--15的位置。这样3个成员共占用了16字节。由于该结构成员c对齐方式为8,是所有成员中最大的,所以结构按8字节对齐,16按8园整还是16,因此sizeof s = 16。

而对于
struct s
{

char a;

long int d;

double c;

char a1;


};//而此时是24
前3个成员和上面一样存储,即a在0位置,d在4--7位置,c在8--16位置,但a1按一字节对齐,存在偏移17位置,这样4个成员占用了17字节;整个结构还要按8对齐为结17按8圆整后是24,因此此时sizeof s = 24。

如果你指定编译器按4字节对齐,即你在开头加上#pragma pack(push,4)
则对于前者为12,后者为16。
我用的是vc7.1。
  回复  更多评论
  

# re: 一个有意思的问题 2006-04-06 11:42 clever101
re发:

照你的说法:
#pragma pack(push,4)

struct s1
{

char a;

long int d;

double c;


};

struct s2
{

char a;

long int d;

double c;

char a1;


};

s1的大小应该是16,s2的大小应该是20。事实上也是这样的。我在VC上作了测试。我的系统环境:win2000,vc6.0。  回复  更多评论
  

# re: 一个有意思的问题 2006-06-30 16:38 cn
对阶!  回复  更多评论
  


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理