[不要只做技术]在论坛上问如下代码结果为什么是24?
union DATE
{
char a;
int i[5];
double b;
};
DATE max;
cout<< sizeof(max) << endl;
这个问题很好回答,并且我把这个问题归结于基本概念题(就是入门书必须介绍的)。我想一般来说,做过内存管理的,对这个语言特性肯定不会陌生。
摘几句The C Programming Language里面讲述这个问题的原话,以说明读书还是必要的:
①联合就是一个结构,②它的所有成员相对于基地址的偏移量都为0,③此结构空间要大到足够容纳最“宽”的成员,④并且,其对齐方式要适合于联合中所有类型的成员。
怕有的兄弟还不明白,特附图一个帮助理解:
char a; | => | x | |||||||||||||||||||||||
int i[5]; | => |
x |
x |
x |
x |
x |
x | ||||||||||||||||||
double b; | => |
x |
|
|
该结构要放得下int i[5]必须要至少占4×5=20个字节。如果没有double的话20个字节够用了,此时按4字节对齐。但是加入了double就必须考虑double 的对齐方式,double是按照8字节对齐的,所以必须添加4个字节使其满足8×3=24,也就是必须也是8的倍数,这样一来就出来了24这个数字。综上 所述,最终联合体的最小的size也要是所包含的所有类型的基本长度的最小公倍数才行。(这里的字节数均指winnt下的值,平台、编译器不同值也有可能 不同。)
联合在存储分配的时候用的机会最多,因为很少有像存储分配这样需要给多种不同类型的变量分配空间而又打算尽可能的节约内存的,这很适合联合的特性。上述对齐的方式有个很有趣的用法也就常在存储分配里面使用。(下面依旧用The C Programming Language中的例子作答)
typedef long Align;
union header {
struct {
union header *ptr;
unsigned size;
} s;
Align x;
}
这里的Align有什么用?作用只有一个,就是强迫分配的结构体按long的长度对齐。
爱书吧,它是知识的源泉!~~
-------------
乾坤一笑 写于2005年8月8日 转载请标明出处和原文链接
#pragma pack( 4 )
union DATE
{
char a;
int i[5];
double b;
};
int main(int argc, char* argv[])
{
DATE max;
std::printf( "%d\r\n",sizeof(max) );
return 0;
}
只是当时觉得你的说法不是很准确,所以贴了这个内存对齐的,用以证实内存对齐需要考虑。
VC6和VC71缺省的是8字节对齐。
“关键不是#pragma,是内存对齐。编译时,都会指定的吧”编译时都会指定什么?#pragma么? 你错了。#pragma这个参数是由编 译器实现的,不同的编译器实现的#pragma都不同。gnu早起版本就把#pragma直接指定到一个游戏上,以讽刺#pragma这种语法。
#pragma主要用来帮助编译器插入各种辅助实现的指令,而不是用来设计代码逻辑。使用#pragma来帮助规划代码逻辑的后果是该代码将不再具有跨平台的能力。另外,非要用#pragma来强制对齐也说明代码本身的设计不合理。
M$之所以这么做,是因为它根本不需要跨平台,它巴不得所有人都套死在它的平台上,跑不了呢。
可以看看VC6和VC7的项目设置,代码生成的设置(缺省是默认,也就是8字节对齐)。至于gcc的缺省对齐是怎么样的,我猜测也是8字节的。
你说的跑游戏的,在你以前的blog里看的过。
我这里写#pragma只是用来指明内存对齐的,不用#pragma指定也可以的,在项目属性上设置就可以了(不修改,缺省的是8字节对齐,所以 也就是你说的24。但是,如果对齐到4字节,所以,我给了那段代码,运行看看(可以去掉#pragma然后在设置上指明4字节对齐))。
那是因为你的对齐是程序员添加的align,而我说的那个是编译器添加的。如果不指出编译器添加的align,恐怕。:]
顺便,没必要程序员对齐,编译器会做,自己额外添加相对对只是浪费内存。没办法了,只能丢一个了 : http://blog.vckbase.com/zhangJW_cn/archive/2005/08/09/10701.html
uvbs引用了该文章,地址:http://blog.csdn.net/UVBS/archive/2006/03/21/630971.aspx
smallball引用了该文章,地址:http://blog.csdn.net/jackfromvia/archive/2006/05/12/725969.aspx
fengsanshao引用了该文章,地址:http://blog.csdn.net/fengsanshao/archive/2007/03/18/1533036.aspx
2. 声明成员应该尽量避免不同类型错杂开来,最好采用从小到大或者从大到小的顺序(错开后,会因为上对齐和下对齐而增加填充开销)。
3. 编译器缺省采用8字节对齐主要是因为最大基本类型为8自己(以前自己不明白,在论坛提过问,后来,以为是SSE指令的原因)。……
sunyonggao引用了该文章,地址:http://blog.csdn.net/sunyonggao/archive/2007/04/23/1576443.aspx
zhy05引用了该文章,地址:http://blog.csdn.net/zhy05/archive/2007/06/06/1641479.aspx
hi_wyl引用了该文章,地址:http://blog.csdn.net/hi_wyl/archive/2007/07/19/1698646.aspx
我也觉得20是正确的呀!