1. 内存对齐

目录

1. 结构体内存对齐规则

2. 为什么存在内存对齐

3. 示例

4. 结构体某个成员相对于结构体起始位置的偏移量


1. 结构体内存对齐规则

  1. 第一个成员在与结构体变量偏移量为0的地址处。(即结构体的首地址处,即对齐到0处)
  2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
  3. 结构体的总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
  4. 如果嵌套了结构体,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

对齐数 = 该结构体成员变量自身的大小与编译器默认的一个对齐数的较小值。

默认对齐值:

        Linux 默认#pragma pack(4)

        window 默认#pragma pack(8)

注:可以通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是指定的“对齐系数”。

注:VS中的默认对齐数为8,不是所有编译器都有默认对齐数,当编译器没有默认对齐数的时候,成员变量的大小就是该成员的对齐数。

2. 为什么存在内存对齐

  • 平台原因(移植原因): 不是所有的硬件平台都能访问任意地址上的任意数据的;某些平台只能在某些地址处取得某些特定类型的数据,否则抛出硬件异常。比如,当一个平台要取一个整型数据时只能在地址为4的倍数的位置取得,那么这时就需要内存对齐,否则无法访问到该整型数据。
  • 性能原因: 数据结构(尤其是栈)应该尽可能的在自然边界上对齐。原因在于,为了访问未对齐内存,处理器需要作两次内存访问;而对齐的内存访问仅需一次。

内存这么重要,在进行内存对齐的时候怎么还有内存被白白浪费掉呢?其实结构体的内存对齐是拿空间来换取时间的做法。

3. 示例

class A
{
public:
    virtual void func() {}

    char a;
    int b;
    double c;
    static int d;
};

解析:

64位机器上:

指针占8个字节,char 占1个字节,int占4个字节, double占8个字节

虚函数表指针从0开始偏移,占用8个字节,占用0-7 ,

接下来是char 占用1个字节,偏移位置8是对齐数(min(1, 8)) 的倍数,所以占有1个字节,占用8

接下来是int 占用4个字节,偏移位置9不是对齐数(min(4, 8))的倍数,所以从从12 开始偏移,占用4个字节 占用12-15 ,

接下来是double 占用8个字节,偏移位置16时对齐数(min(8,8))的倍数,所以从从12开始偏移,占用8个字节,占用16-23

所以从 0~23 一共24个字节,24为最大对齐数(max(1,4,8))的整数倍,故而,该结构体大小为24个字节。

4. 结构体某个成员相对于结构体起始位置的偏移量

使用offsetof宏来判断结构体中成员的偏移地址。使用offsetof宏需要包含stddef.h头文件,该宏定义如下:

 #define offsetof(type,menber) (size_t)&(((type*)0)->member)

                
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值