随笔 - 119  文章 - 290  trackbacks - 0

博客搬家了哦,请移步
叫我abc

常用链接

留言簿(12)

随笔分类

我的博客

搜索

  •  

积分与排名

  • 积分 - 301918
  • 排名 - 84

最新评论

阅读排行榜

#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 阅读(1735) 评论(3)  编辑 收藏 引用

FeedBack:
# re: bugfix:模板结构的跨平台差异 2010-01-09 21:14 tanchuhan
没必要用#pragma pack(1), 自己定义结构时记得对齐就是了,你看Windows里的绝大部分struct都是4字节对齐的(空位可以用reserved命名).
对齐肯定是有很多好处的,不然编译器干嘛费心去对齐结构里的字段.  回复  更多评论
  
# re: bugfix:模板结构的跨平台差异 2010-01-09 23:10 LOGOS
@tanchuhan
记得对齐其实要求很高的智力与注意力
在网络消息结构里,非常关心实际的对齐大小,一定会进行显式的设置,不管是通过工程配置还是代码
按1字节对齐,这个现状比较普遍  回复  更多评论
  
# re: bugfix:模板结构的跨平台差异 2010-01-10 15:10 littlewater
显然,在通讯里面使用C++的结构而不是POD,不是一种明智的做法-x-  回复  更多评论
  

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