#pragma pack(1)
struct Base
{
int a;
char b;
int c;
};
template<typename T>
struct Child_X : public Base
{
T data[1];
};
#pragma pack()
猜一下下面两个sizeof的结果:
sizeof(Base)
sizeof(Child_X<int>)
sizeof(Base) = 9。一些猜对或者没猜对的同学应该用google好好补充一下基础知识。
sizeof(Child_X<int>) = sizeof(Base) + sizeof(int) = 13。
应该是13,但是16也是对的,这就是编译器的差异。
M$的VS2008,执行的结果是 sizeof(Child_X<int>) = 13。
linux的gcc-4.4,执行结果是 sizeof(Child_X<int>) = 16。
当两个平台编译的程序互相通讯,消息里面包含Child_X<>结构时,肯定会发生一些不那么有趣的事情。
这个不有趣的事情大概有两种表现形式:
1.当你明显的执行一个操作后,收到一条不太对头的Child_X消息,程序崩溃了。这种的问题很容易查。
2.当你执行或者不执行操作,不久程序崩溃了,根据崩溃看起来是某处内存写串了,而你在这段时间内没有收到任何Child_X消息。
不幸的是我遇上的就是第二种情况,这种情况麻烦的地方就在于崩溃的位置和崩溃的原因之间有一段不会太短的距离,其本质就是大小不正确的Child_X消息初始化程序,结果程序的状态是不正确的,但是这个不正确的状态直到不久使用某些操作才引起严重错误,而错误看起来就像是内存写串了。
造成这种差异的原因是,VC在实例化模板的时候,使用了定义模板的上下文;而gcc在实例化模板的时候,则使用的是第一次实例化模板的那段代码的上下文。
我想标准肯定没有规定这个细节,不过VC的实现方案更符合常规的心里预期。而标准委员会除了开会吵架,已经很久没有作为了。
最后跨平台的解决方案是,在pack上下文里对模板进行实例化
#pragma pack(1)
template<typename T>
struct Child_X : public Base
{
T data[1];
};
template struct Child_X<short>;
template struct Child_X<int>;
// 不过这种方案只能用来对付需要实例化的类型数量较少的情况
#pragma pack()
posted on 2010-01-09 20:20
LOGOS 阅读(1724)
评论(3) 编辑 收藏 引用