结构体在内存中的对齐和补齐是怎么回事?

时间:2021-01-17 10:34:08
想请教大家有关于结构体在内存中的对齐和补齐是怎么回事?

9 个解决方案

#1


参考这篇(http://www.cnblogs.com/dabiao/archive/2010/04/15/1712458.html)文章。

#2


成员起始位置必须是某个值(m)的整数倍
结构体总大小必须是某个值(n)的整数倍,不足的要补齐

m=min(sizeof(该成员的类型),k)
n=min(sizeof(最大基本成员的类型),k)

k指指定值,vs2008默认是8

#3


引用 2 楼  的回复:
成员起始位置必须是某个值(m)的整数倍
结构体总大小必须是某个值(n)的整数倍,不足的要补齐

m=min(sizeof(该成员的类型),k)
n=min(sizeof(最大基本成员的类型),k)

k指指定值,vs2008默认是8
5Linux下K是多少?

#4


引用 1 楼  的回复:
参考这篇(http://www.cnblogs.com/dabiao/archive/2010/04/15/1712458.html)文章。

哥们你给我看的那篇文章太深奥,能不能通俗点解释?

#5


结构体对齐是为了便于CPU取指令,所以在存储数据时会有填充字节。对于对齐方式和对齐长度,windows下和linux下是有区别的;linux下最大的对齐长度是4个字节,即在结构体中元素长度超过4个字节数据,也是按4字节对齐;对于元素长度最大值小于4个字节的,按最大长度对齐即linux下结构体对齐长度有1、2、4;在windows下,没有最大对齐方式的限制。

#6


struct A
{
   int n;
   char c;
   long l;
};

这个结构体多大??

是3 * 4 = 12个字节, 而非 4 + 1+4=9个字节。。 这就是补齐。
为了能够快速处理, 将中间的c补充成为4个字节。统一处理。。

同样
struct B
{
   int n;
   char c1;
   char c2;
   long l;
};
同样, B也是12个字节, 将c1,c2补充成为4个字节,统一处理。。

#7


引用 6 楼  的回复:
struct A
{
  int n;
  char c;
  long l;
};

这个结构体多大??

是3 * 4 = 12个字节, 而非 4 + 1+4=9个字节。。 这就是补齐。
为了能够快速处理, 将中间的c补充成为4个字节。统一处理。。

同样
struct B
{
  int n;
  char c1;
  char c2;
  long l;……
能不能再通俗点,我还是理解不了

#8


说白了就是对于这样的结构体
struct A
{
int n;
char c;
long l;
};
由于 最大的结构是4字节,所以都以4字节为整体分配空间,  这样方便CPU取值。 若不是对齐的,cpu会第一次读入4字节数据, 第二次读入1字节的数据, 不能直接区分, 所以需要额外的开销高速cpu本次读入多少字节。

所以给第二个变量c直接分配4个字节补齐数据。
struct B
{
int n;
char c;
char c2;
long l;
};

struct C
{
int n;
char c;
char c2;
char c3;
long l;
};

struct D
{
int n;
char c;
char c2;
char c3;
char c4;
long l;
};

上述4个结构体 都是12个字节大小。其中A中的 字符c补齐成4个字节, B中的 c,c1 只有2B,补齐成为4B。同理……

可想而知
struct E
{
int n;
struct D d;
}; 
他有多大?? 一样的道理

#9


 结构在内存的存储空间一般来说大小相当于结构体各成员变量的内存大小之和。但在内存中的具体存储方式却不尽是这样的,看下面两个例子:
例一:
#include<stdio.h>  
typedef struct Goods{ char name[18] ;//占18个字节  double price ;//占8个字节 char special ;//占1个字节int num ;//占4个字节  }gs ;  
int  main(){  
    gs  g ; 
    printf("%d\n", sizeof(gs)) ;
    return 0; 
}
结果输出的是36。
例二:
#include<stdio.h>    
typedef struct Goods{ char name[18] ;//占18个字节  double price ;//占8个字节 char special ;//占1个字节int num ;//占4个字节 short saled ;//占2个字节  }gs ;      
int  main(){  
     gs  g ; 
     printf("%d\n", sizeof(gs)) ; 
     return 0; 
}
结果输出的是40。
为什么是这样的呢,因为结构在内存中存储需要遵守补齐和对齐的规则。
对齐:结构中各成员变量要从自身类型所占内存空间长度的倍数开始存储。大于4个字节的按4个字节算。
补齐:在结构存储空间的尾端要按结构体所占空间最大的成员变量的所占空间长度的倍数来补上。大于4个字节的按4个字节算。
           补齐是为了让多个结构体挨个存储的时候,也能够满足对齐的规则。
例一中,假设该结构体是从0地址开始存储,name占了18个字节,然后price对齐到20地址(20是4的倍数)开始,占了8个字节,special从28地址开始,占了1个字节,num从32地址(32是4的倍数)开始,占了4个字节,最后36是4的倍数,不需要补齐。所以输出是36。
例二中,假设该结构体是从0地址开始存储,name占了18个字节,然后price对齐到20地址(20是4的倍数)开始,占了8个字节,special从28地址开始,占了1个字节,num从32地址(32是4的倍数)开始,占了4个字节,saled从36地址开始,占了2个字节,38不是4的倍数,需要补齐到40地址,所以输出的是40。
        神奇就是这么来的,在内存中,对齐原则是为了提高访问效率,合理的编排结构体成员变量的顺序可以节省内存空间,看例子:
例三:
#include<stdio.h>    
typedef struct Goods{ char name[18] ;//占18个字节  short saled ;//占2个字节  double price ;//占8个字节 int num ;//占4个字节  char special ;//占1个字节 }gs ;      
int  main(){  
     gs  g ; 
     printf("%d\n", sizeof(gs)) ; 
     return 0; 
}     假设该结构体是从0地址开始存储,name占了18个字节,saled从18地址开始,占了2个字节,然后price从20地址开始,占了8个字节,num从28地址(28是4的倍数)开始,占了4个字节,special从32地址开始,占了1个字节,33不是4的倍数,需要补齐到36地址,所以输出的是36,相对于40来说节省了4个字节的内存空间。

#1


参考这篇(http://www.cnblogs.com/dabiao/archive/2010/04/15/1712458.html)文章。

#2


成员起始位置必须是某个值(m)的整数倍
结构体总大小必须是某个值(n)的整数倍,不足的要补齐

m=min(sizeof(该成员的类型),k)
n=min(sizeof(最大基本成员的类型),k)

k指指定值,vs2008默认是8

#3


引用 2 楼  的回复:
成员起始位置必须是某个值(m)的整数倍
结构体总大小必须是某个值(n)的整数倍,不足的要补齐

m=min(sizeof(该成员的类型),k)
n=min(sizeof(最大基本成员的类型),k)

k指指定值,vs2008默认是8
5Linux下K是多少?

#4


引用 1 楼  的回复:
参考这篇(http://www.cnblogs.com/dabiao/archive/2010/04/15/1712458.html)文章。

哥们你给我看的那篇文章太深奥,能不能通俗点解释?

#5


结构体对齐是为了便于CPU取指令,所以在存储数据时会有填充字节。对于对齐方式和对齐长度,windows下和linux下是有区别的;linux下最大的对齐长度是4个字节,即在结构体中元素长度超过4个字节数据,也是按4字节对齐;对于元素长度最大值小于4个字节的,按最大长度对齐即linux下结构体对齐长度有1、2、4;在windows下,没有最大对齐方式的限制。

#6


struct A
{
   int n;
   char c;
   long l;
};

这个结构体多大??

是3 * 4 = 12个字节, 而非 4 + 1+4=9个字节。。 这就是补齐。
为了能够快速处理, 将中间的c补充成为4个字节。统一处理。。

同样
struct B
{
   int n;
   char c1;
   char c2;
   long l;
};
同样, B也是12个字节, 将c1,c2补充成为4个字节,统一处理。。

#7


引用 6 楼  的回复:
struct A
{
  int n;
  char c;
  long l;
};

这个结构体多大??

是3 * 4 = 12个字节, 而非 4 + 1+4=9个字节。。 这就是补齐。
为了能够快速处理, 将中间的c补充成为4个字节。统一处理。。

同样
struct B
{
  int n;
  char c1;
  char c2;
  long l;……
能不能再通俗点,我还是理解不了

#8


说白了就是对于这样的结构体
struct A
{
int n;
char c;
long l;
};
由于 最大的结构是4字节,所以都以4字节为整体分配空间,  这样方便CPU取值。 若不是对齐的,cpu会第一次读入4字节数据, 第二次读入1字节的数据, 不能直接区分, 所以需要额外的开销高速cpu本次读入多少字节。

所以给第二个变量c直接分配4个字节补齐数据。
struct B
{
int n;
char c;
char c2;
long l;
};

struct C
{
int n;
char c;
char c2;
char c3;
long l;
};

struct D
{
int n;
char c;
char c2;
char c3;
char c4;
long l;
};

上述4个结构体 都是12个字节大小。其中A中的 字符c补齐成4个字节, B中的 c,c1 只有2B,补齐成为4B。同理……

可想而知
struct E
{
int n;
struct D d;
}; 
他有多大?? 一样的道理

#9


 结构在内存的存储空间一般来说大小相当于结构体各成员变量的内存大小之和。但在内存中的具体存储方式却不尽是这样的,看下面两个例子:
例一:
#include<stdio.h>  
typedef struct Goods{ char name[18] ;//占18个字节  double price ;//占8个字节 char special ;//占1个字节int num ;//占4个字节  }gs ;  
int  main(){  
    gs  g ; 
    printf("%d\n", sizeof(gs)) ;
    return 0; 
}
结果输出的是36。
例二:
#include<stdio.h>    
typedef struct Goods{ char name[18] ;//占18个字节  double price ;//占8个字节 char special ;//占1个字节int num ;//占4个字节 short saled ;//占2个字节  }gs ;      
int  main(){  
     gs  g ; 
     printf("%d\n", sizeof(gs)) ; 
     return 0; 
}
结果输出的是40。
为什么是这样的呢,因为结构在内存中存储需要遵守补齐和对齐的规则。
对齐:结构中各成员变量要从自身类型所占内存空间长度的倍数开始存储。大于4个字节的按4个字节算。
补齐:在结构存储空间的尾端要按结构体所占空间最大的成员变量的所占空间长度的倍数来补上。大于4个字节的按4个字节算。
           补齐是为了让多个结构体挨个存储的时候,也能够满足对齐的规则。
例一中,假设该结构体是从0地址开始存储,name占了18个字节,然后price对齐到20地址(20是4的倍数)开始,占了8个字节,special从28地址开始,占了1个字节,num从32地址(32是4的倍数)开始,占了4个字节,最后36是4的倍数,不需要补齐。所以输出是36。
例二中,假设该结构体是从0地址开始存储,name占了18个字节,然后price对齐到20地址(20是4的倍数)开始,占了8个字节,special从28地址开始,占了1个字节,num从32地址(32是4的倍数)开始,占了4个字节,saled从36地址开始,占了2个字节,38不是4的倍数,需要补齐到40地址,所以输出的是40。
        神奇就是这么来的,在内存中,对齐原则是为了提高访问效率,合理的编排结构体成员变量的顺序可以节省内存空间,看例子:
例三:
#include<stdio.h>    
typedef struct Goods{ char name[18] ;//占18个字节  short saled ;//占2个字节  double price ;//占8个字节 int num ;//占4个字节  char special ;//占1个字节 }gs ;      
int  main(){  
     gs  g ; 
     printf("%d\n", sizeof(gs)) ; 
     return 0; 
}     假设该结构体是从0地址开始存储,name占了18个字节,saled从18地址开始,占了2个字节,然后price从20地址开始,占了8个字节,num从28地址(28是4的倍数)开始,占了4个字节,special从32地址开始,占了1个字节,33不是4的倍数,需要补齐到36地址,所以输出的是36,相对于40来说节省了4个字节的内存空间。