最近调试网络的服务端程序,自己写了一个小客户端程序来测试,发现服务程序解包错误。经调试发现客户端的协议头大小和服务器端的协议头大小不一致。原因是服务器端加了#pragma pack(1),而客户端没加。

    之前没接触过这个编译宏,现在来认真学习之。

    首先google~~

    原来#pragma pack有几种形式,我所接触到的是#pragma pack(n),即变量以n字节对齐。

    变量对齐在每个系统中是不一样的,默认的对齐方式能有效的提高cpu取指取数的速度,但是可能会浪费一定的空间。在网络程序中采用#pragma pack(1),即变量紧缩,不但可以减少网络流量,还可以兼容各种系统,不会因为系统对齐方式不同而导致解包错误。

    了解了概念和优点,现在我们就来测试之~

 

    平台:CPU—Pentium E5700 内存—2G

     1.操作系统:ubuntu 11.04 32bit   编译器:G++ 4.5.2

     2.操作系统:windows xp              编译器:VS2010

 

    先看第一个测试。

    结构体在正常情况和紧缩情况在以上不同环境下占用的内存大小。

1 struct pack {
2   int i;
3   short s;
4   double d;
5   char c;
6   short f;
7 }

  
   测试结果为:

    1
   

 

    2
    
  
    测试结果分析:

 

 

    可以看出紧缩后结构体的大小为15,是结构体内置类型大小的和。但是在默认情况下,结构体的大小都是对齐字节数的倍数。ubuntupack只需要20个字节,而windows24个字节。这是因为ubuntu是以4字节对齐,而windows则是以最大的内置类型的字节数对齐,在结构体内最大的内置类型为double,其大小为8个字节。他们在内存中的对齐方式如下图:

    1

    

    2

    

   还需注意的是,在对齐类型的内部都是以2字节对齐的。

   结论:在默认情况下,linux操作系统是以4字节对齐,windows操作系统则是以最大的内置类型对齐。

 

   第二个测试

   一个结构体内包含另外一个结构体,其大小的情况。

   内部的结构体为

1 struct pack {
2   short s;
3   double d;
4 }

   外部的结构体为

   1 struct complex _pack{

2   char c;
3   struct pack s;
4   double d;
5 };

    我们有四种情况:

     1.      pack紧缩,complex _pack紧缩

     2.      pack紧缩,complex _pack默认

     3.      pack默认,complex _pack紧缩

     4.      pack默认,complex _pack默认

    以下的排列均按此顺序。

     测试的结果

      1

      

     2

      

    测试结果分析:

    在两个操作系统下,除了第一种情况----内结构体和外结构体都紧缩----相同之外,其他三种情况都不相同。我们可以根据偏移画出结构体在内存中的情况。第一种情况省略。

     1

     

     2

     

    结论:#pragma pack只影响当前结构体的变量的对齐情况,并不会影响结构体内部的结构体变量的排列情况。或者说#pragma pack的作用域只是一层。我们由第三种情况,内部结构体正常,外部结构体紧缩,可以得出结构体的对齐是按偏移计算的。

    这里还有一个问题没解决,为什么第二种情况内部结构体的偏移都是1?不是4或者8?

 

posted on 2011-07-15 20:36 Range 阅读(6138) 评论(6)  编辑 收藏 引用
评论
  • # re: #pragma pack学习
    13174115@qq.com
    Posted @ 2011-07-16 12:50
    楼主你的画图工具不错啊,是什么呢?
      回复  更多评论   
  • # re: #pragma pack学习
    johnnie
    Posted @ 2011-07-20 12:50
    我觉得pack(4)已经OK了,没必要pack(1),毕竟对齐是为了方便自己的CPU。
    要减少网络流量的话,可以在发数据前将其压缩一下,收之前再解压一次。  回复  更多评论   
  • # re: #pragma pack学习
    Range
    Posted @ 2011-07-21 16:37
    @johnnie

    pack(4)的确是很好的建议,但是具体的情况还需要应用。

    IM,bittorrent 这种网络程序一般都是IO-bound。CPU的消耗不是很大吧。  回复  更多评论   
  • # re: #pragma pack学习
    Range
    Posted @ 2011-07-21 16:38
    @13174115@qq.com

    visio  回复  更多评论   
  • # re: #pragma pack学习
    刘明杰
    Posted @ 2011-07-21 17:35
    这个15怎么来的,4+2+8+1+2=17,而且我vs2008上跑了也是17。。。。。  回复  更多评论   
  • # re: #pragma pack学习
    Range
    Posted @ 2011-07-22 10:29
    @刘明杰

    谢谢你的提醒,我回头看了下代码,pack(1)时候的代码,没加short f。

    short f是我后来加上去的,为的是看出在默认情况下,内部会以2字节对齐。  回复  更多评论   

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


统计