CSDN首页 空间 新闻 论坛 Blog 下载 读书 网摘 搜索 .NET Java 视频 接项目 求职 在线学习 买书 程序员 通知
可用分押宝游戏火热进行中... 专题改版:Java Web 专题
CSDN社区
搜索 收藏 打印 关闭
CSDN社区 >  C/C++ >  C++ 语言

关于字节对齐的问题。

楼主yndfcd(YNDFCD)2005-08-08 16:48:52 在 C/C++ / C++ 语言 提问

先看程序:  
  #pragma   pack(8)  
   
  struct   s1{  
  short   a;  
  long   b;  
  };  
   
  struct   s2{  
  char   c;  
  s1   d;  
  __int64   e;  
  };  
   
  #pragma   pack()  
   
  int   main(int   argc,   char*   argv[])  
  {  
  s2   a;  
  s2*   pa   =   &a;  
  char*   pc   =   &a.c;  
  s1*   pd   =   &a.d;  
  __int64*   pe   =   &a.e;  
  printf("sizeof(   s2   )   =   %d,   sizeof(   s1   )   =   %d",   sizeof(   s2   ),sizeof(   s1   )   );  
  printf(   "\n0x%8x\n0x%8x\n0x%8x\n0x%8x\n",   pa,   pd,   pc,   pe   );  
  return   0;  
  }  
   
  下面是输出:  
  sizeof(   s2   )   =   24,   sizeof(   s1   )   =   8  
  0x     65fde0  
  0x     65fde0  
  0x     65fde4  
  0x     65fdf0  
  Press   any   key   to   continue  
   
  问题一:为什么s2::d会出现在0x65fde4的位置上(8字节对齐,理论上应该出现在0x65fde8)?  
  问题三:为什么s2::d会占用12个字节? 问题点数:100、回复次数:17Top

1 楼Diego1983(不再犹豫!)回复于 2005-08-08 17:09:51 得分 0

很麻烦啊,晕了  
   
  想问句,我想学MFC,从哪本书开始啊,  
  我看WINDOWS程序设计,有点迷糊,看不很懂啊  
  介绍下啊Top

2 楼aiguozhou(想起)回复于 2005-08-08 17:19:25 得分 0

《精通MFC程序设计》Top

3 楼dongpy(51-->ARM)回复于 2005-08-08 17:20:51 得分 30

问题一:为什么s2::d会出现在0x65fde4的位置上  
  ======================================================  
  s2::d是4字节对齐的  
   
  问题三:为什么s2::d会占用12个字节?  
  ==========================  
  s2::d占8字节Top

4 楼dongpy(51-->ARM)回复于 2005-08-08 17:23:28 得分 0

struct   s2变量内存布局:  
   
  c   ***   d   ****   e     (*是1字节的补齐字节)Top

5 楼Diego1983(不再犹豫!)回复于 2005-08-08 17:25:14 得分 0

听说还有本《深入浅出MFC》  
  不知道哪本更加好啊??Top

6 楼LoveYouJustOneDay(哈哈)回复于 2005-08-08 18:17:08 得分 40

到处搜刮来的,整理了一下。  
   
  为了能使CPU对变量进行高效快速的访问,变量的起始地址应该具有某些特性,  
  即所谓的“对齐”。例如对于4字节的int类型变量,其起始地址应位于4字节边界上,  
  即起始地址能够被4整除。变量的对齐规则如下(32位系统):  
   
   
  Type  
  Alignment  
   
  char  
  在字节边界上对齐  
   
  short   (16-bit)  
  在双字节边界上对齐  
   
  int   and   long   (32-bit)  
  在4字节边界上对齐  
   
  float  
  在4字节边界上对齐  
   
  double  
  在8字节边界上对齐  
   
   
   
  structures  
  单独考虑结构体的个成员,它们在不同的字节边界上对齐。  
  其中最大的字节边界数就是该结构的字节边界数。  
  MSDN原话:Largest   alignment   requirement   of   any   member  
  理解结构体的对齐方式有点挠头,如果结构体中有结构体成员,  
  那么这是一个递归的过程。  
  对齐方式影响结构体成员在结构体中的偏移设编译器设定的最大对齐字节边界数为n,  
  对于结构体中的某一成员item,它相对于结构首地址的实际字节对齐数目X应该满足  
  以下规则:  
   
  X   =   min(n,   sizeof(item))  
   
  例如,对于结构体   struct   {char   a;   int   b}   T;  
   
  当位于32位系统,n=8时:  
  a的偏移为0,  
  b的偏移为4,中间填充了3个字节,   b的X为4;  
   
  当位于32位系统,n=2时:  
  a的偏移为0,  
  b的偏移为2,中间填充了1个字节,b的X为2;  
   
  结构体的sizeof  
  设结构体的最后一个成员为LastItem,其相对于结构体首地址的  
  偏移为offset(LastItem),其大小为sizeof(LastItem),结构体的字节对齐数为N,  
  则:结构体的sizeof   为:   若offset(LastItem)+   sizeof(LastItem)能够被N整除,  
  那么就是offset(LastItem)+   sizeof(LastItem),否则,在后面填充,  
  直到能够被N整除。  
   
  例如:32位系统,n=8,  
  结构体   struct   {char   a;   char   b;}   T;  
  struct   {char   a;   int   b;}   T1;  
  struct   {char   a;   int   b;   char   c;}   T2;  
  sizeof(T)   ==   2;   N   =   1   没有填充  
  sizeof(T)   ==   8;   N   =   4   中间填充了3字节  
  sizeof(T2)==12;   N   =   4   中间,结尾各填充了3字节  
   
  注意:  
   
  1)   对于空结构体,sizeof   ==   1;因为必须保证结构体的每一个实例在内存中都  
  有独一无二的地址。  
   
  2)   结构体的静态成员不对结构体的大小产生影响,因为静态变量的存储位置与  
  结构体的实例地址无关。  
   
  例如:  
   
  struct   {static   int   I;}   T;   struct   {char   a;   static   int   I;}   T1;  
  sizeof(T)   ==   1;   sizeof(T1)   ==   1;  
   
  3)   某些编译器支持扩展指令设置变量或结构的对齐方式,如VC,  
      详见MSDN(alignment   of   structures)  
   
  以下为Linux内核代码中的例子:  
   
  __attribute__((regparm(0)))   int   printk(const   char   *   fmt,   ...)\  
    __attribute__   ((format   (printf,   1,   2)));  
  禁止printk使用寄存器传递调用参数,并将printk的参数1作为printf格式串,  
  从参数2开始检查其类型;  
   
  void   __switch_to(struct   task_struct   *prev,   struct   task_struct   *next)\  
    __attribute__((regparm(3)))   ;__switch_to保留3个寄存器用作传递参数;  
   
  void   __attribute__   ((__section__   (".text.init")))   mem_init();  
  将mem_init编绎到.text.init段;  
   
  struct   tasklet_head   tasklet_vec[32   ]\  
    __attribute__((__aligned__((32)),__section__(".data.cacheline_aligned")))   ;  
  将tasklet_vec[32]编绎到.data.cacheline_aligned段,并将它在32字节边界上对齐;  
   
  void   do_exit(long   error_code)__attribute__((noreturn));do_exit不会返回;  
   
  struct   Xgt_desc_struct   {   unsigned   short   size;   unsigned   long\  
  address   __attribute__((packed));};将address在结构中紧凑排列。  
  Top

7 楼yndfcd(YNDFCD)回复于 2005-08-08 19:38:35 得分 0

多谢楼上的。Top

8 楼yndfcd(YNDFCD)回复于 2005-08-08 19:59:24 得分 0

但是还是没有完全解决我的问题,看MSDN上的原话:  
   
  Every   data   object   has   an   alignment-requirement.   For   structures,   the   requirement   is   the   largest   of   its   members.   Every   object   is   allocated   an   offset   so   that  
   
  offset   %   alignment-requirement   ==   0  
   
  每个数据对象都有一个alignment-requirement.对于结构体来说,Requirement   就是最大的成员。(似乎MSDN上这句话本身就是错的,到少应该是最大成员所占内存的大小)。每一个对象被放置在offset处,其中offset   满足   offset   %   alignment-requirement   ==   0;  
   
  按照上面的理论,s2的最大成员的大小为8,那么每个成员都应该被放置在   offset   %   8   ==   0的位置上。即0,   8   ,   16   .....。(难道我的理解错了?或者是MSDN写错了)。  
   
  另外,如果我交换结构体s2中   d,   和   c的位置:  
      struct   s3  
  {    
        s1   d;  
        char   c;  
        __int64   e;  
  }    
  得到的c就位于相对offset为8的位置上,而e位于相对offset为16的位置。Top

9 楼jiajun2001(Jagen(嘉俊))回复于 2005-08-08 20:49:48 得分 0

并不是要求#pragma   pack(8),就一定是每个成员都是8字节对齐  
  而是指一组成员要按照8字节对齐。  
  struct   s1  
  {  
        short   a;       //   2字节  
        long   b;         //   4字节  
  };  
  整个s1小于8字节,因此s1就是8字节。  
   
  struct   s2  
  {  
        char   c;         //   1字节  
        s1   d;             //   8字节  
        __int64   e;   //   8字节  
  };  
  整个s2小于12字节,但是由于#pragma   pack(8)的限定,12不能与8字节对齐,因此s2就是24字节,c占用8字节  
   
  Top

10 楼defyer007(深入浅出)回复于 2005-08-08 23:38:59 得分 0

学习...  
  我觉得应该还要注意它的起始地址  
  如果起始地址就不对齐的话,那可能后面需要填补更多的空字节,而造成大小的不同Top

11 楼cnwhonker(龙神)回复于 2005-08-09 08:09:55 得分 0

孤独小胖,帮你顶一下,Top

12 楼yndfcd(YNDFCD)回复于 2005-08-09 08:18:53 得分 0

jiajun2001(嘉俊)   你是不是看错了,   c明显只占用了4字节,而d占用了12字节。如果c占用8字节我就不会来问了。Top

13 楼yndfcd(YNDFCD)回复于 2005-08-09 08:28:14 得分 0

上面的程序可能写错了一点,修改一下:  
   
  printf(   "\n0x%8x\n0x%8x\n0x%8x\n0x%8x\n",   pa,   pc,   pd,   pe   );  
   
  输出:  
   
  sizeof(   s2   )   =   24,   sizeof(   s1   )   =   8  
  0x     65fdd4  
  0x     65fdd4  
  0x     65fdd8  
  0x     65fde4  
  Press   any   key   to   continue  
  Top

14 楼ken0426(绅士亦花心)回复于 2005-08-09 11:10:35 得分 30

Search   FAQ,   please.Top

15 楼weiym(磨刀霍霍向猪羊)回复于 2005-08-09 13:06:05 得分 0

markTop

16 楼yndfcd(YNDFCD)回复于 2005-08-09 15:05:26 得分 0

明白了,谢谢Top

17 楼Poptang(苦命的娃)回复于 2005-11-15 11:07:34 得分 0

markTop

相关问题

  • 何谓“字节对齐”
  • 字节对齐问题
  • 关于字节对齐
  • 字节对齐问题
  • 在unix下的字节对齐问题??
  • 奇特的双字节对齐问题。
  • Linux下的字节对齐问题
  • 字节对齐是什么意思啊?
  • 关于字节对齐问题????????????????
  • WinCE 下字节对齐问题

关键词

  • 结构
  • 内存
  • msdn
  • 结构体
  • lastitem
  • 变量
  • fde
  • 偏移
  • 成员
  • 填充

得分解答快速导航

  • 帖主:yndfcd
  • dongpy
  • LoveYouJustOneDay
  • ken0426

相关链接

  • C/C++ Blog
  • C/C++类图书
  • C/C++类源码下载

广告也精彩

反馈

请通过下述方式给我们反馈
反馈
提问
网站简介|广告服务|VIP资费标准|银行汇款帐号|网站地图|帮助|联系方式|诚聘英才|English|问题报告
世纪乐知(北京)网络技术有限公司 版权所有, 京 ICP 证 020026 号
北京创新乐知广告有限公司 提供技术支持
Copyright © 2000-2007, CSDN.NET, All Rights Reserved
GongshangLogo