C/C++编程:结构体默认对齐方式

1059 篇文章 284 订阅

什么是内存对齐

还是用一个例子带出这个问题,看下面的小程序,理论上,32位系统下,int占4byte,char占一个byte,那么将它们放到一个结构体中应该占4+1=5byte;但是实际上,通过运行程序得到的结果是8 byte,这就是内存对齐所导致的。

#include<stdio.h>
struct{
    int x;
    char y;
}s;

int main()
{
    printf("%d\n",sizeof(int));  // 4
    printf("%d\n",sizeof(char)); // 1
    printf("%d\n",sizeof(s));  // 输出8
    return 0;
}

现代计算机中内存空间都是按照 byte 划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但是实际的计算机系统对基本类型数据在内存中存放的位置有限制,它们会要求这些数据的首地址的值是某个数k(通常它为4或8)的倍数,这就是所谓的内存对齐。

为什么要进行内存对齐

1.平台原因(移植原因): 一些资料上是这样说的,“不是所有的硬件平台都能访问任意地址上的任意数据;某些硬件平台只能在某些特定地址处取某些特定的数据,否则就会抛出硬件异常”。也就是说在计算机在内存读取数据时,只能在规定的地址处读数据,而不是内存中任意地址都是可以读取的。

2.效率原因: 正是由于只能在特定的地址处读取数据,所以在访问一些数据时,对于访问未对齐的内存,处理器需要进行两次访问;而对于对齐的内存,只需要访问一次就可以。 其实这是一种以空间换时间的做法,但这种做法是值得的。

结构体默认对齐

规则

  • 对于结构体中的各个成员,第⼀个成员位于偏移为 0 的位置,以后的每个数据成员的偏移ᰁ必须是min(#pragma pack() 制定的数,数据成员本身⻓度) 的倍数。
  • 在所有的数据成员完成各⾃对⻬之后,结构体或联合体本身也要进⾏对⻬,整体⻓度是 min(#pragma pack()制定的数,⻓度最⻓的数据成员的⻓度) 的倍数。
  • 64位操作系统上64位编译器:默认8字节对齐
  • 64位操作系统上32位编译器:默认8字节对齐
  • 32位操作系统上32位编译器:默认4字节对齐

以下两点是对于64位操作系统上64位编译器:默认8字节对齐而言的,如果是4字节对齐,只需要将8改成4即可:

  • 结构体整体本身安置在8字节对齐处,结构体对齐后的大小必须是8的倍数
  • 结构体中每个元素占的字节大小是自身对齐参数的整数倍

以下是32/64位Linux上GCC编译环境下各类型变量的自身对齐参数
在这里插入图片描述

编译器考虑结构体存放时,以满足以上2点要求的最少内存需要来存放。

分析

1、


typedef struct struct_test1
{
    int a;   // 4
    double b;  // 8
    char c;  // 1
}ST1;
int main(void)
{
    printf("sizeof(ST1) = %d\n", (int)sizeof(ST1));  // 24
    char *p = NULL;//根据指针长度来辨别编译器和操作系统位数
    printf("sizeof(p)   = %d\n", (int)sizeof(p));  //8
    return 0;
}

64位操作系统上默认是8字节对齐,整体所占字节数分析如下:

  • 首先整个结构体本身安置在8字节对齐处,这个是由编译器保证的。
  • 然后是第一个元素a,a的开始地址就是整个结构体的开始地址,所以自然是8字节对齐的。但是a的结束地址要由下一个元素具体决定
  • 之后是第二个元素b,b为double型的,自身对齐长度是8,所以不能自接放在a的后面,也就是说a需要另外填充4个字节空间再结束,然后放b,由于b本身就是对齐的,所以无需另外填充,直接结束
  • 直接放c,c放完之后也不能自接结束,因为要保证整个结构体大小是8的整数倍,所以c后面需填充7个字节的内存空间。
    在这里插入图片描述
    所以sizeof(ST1) = (4 + 4) + 8 + (1 + 7) = 24;
#include <stdio.h>
typedef struct mystruct1
{
    int a;
    char b;
    double c;
}MS1;//16

typedef struct mystruct2
{
    char a;
    char b[15];
    char c;
    char *p;
}MS2;//(1+15)+(1+7)+8 = 32

typedef struct mystruct3
{
    char a;
    char b[17];
    char c;
    char *p;
}MS3;//(1+17+1+5)+8 =32

typedef struct mystruct4
{
    struct mystruct1 mys1;
    short b[5];
}MS4;//32

int main(void)
{
    printf("sizeof(MS1) = %ld\n", sizeof(MS1));
    printf("sizeof(MS2) = %ld\n", sizeof(MS2));
    printf("sizeof(MS3) = %ld\n", sizeof(MS3));
    printf("sizeof(MS4) = %ld\n", sizeof(MS4));
    return 0;
}

在这里插入图片描述

  • 7
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值