C语言中的内存对齐

独自空忆成欢 提交于 2019-12-05 17:27:17

什么是内存对齐

内存对齐”应该是编译器的“管辖范围”。编译器为程序中的每个数据单元安排在适当的位置上。

出现原因( 老生常谈的两句话 )

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

对齐规则

  • 第一个成员放在偏移量(offset)为0的地方。
  • 以后的每个成员的偏移量:min(#pragma pack()指定的数值,当前成员的大小)的倍数中。
  • 每个成员对齐后,本身也要对齐,整体的偏移量:min(#pragma pack()指定的数值,结构体最大数据成员的大小)。

关于 #pragma pack

  • 通过#pragma pack(n)来设定变量以n字节对齐方式
  • n字节对齐就是说变量存放的起始地址的偏移量有两种情况
    • 如果n大于等于该变量所占用的字节数,那么偏移量必须满足默认的对齐方式 。
    • 果n小于该变量的类型所占用的字节数,那么偏移量为n的倍数,不用满足默认的对齐方式 。
  • 32位系统默认为4,64位系统默认为8。

举个例子🌰

#include<stdio.h>
#pragma pack(4)

struct Node{
    char a;
    char b;
    int c;
};
int main(void){
    printf("%d",sizeof(struct Node));
    return 0;
} 
  • 首先看规则1,成员变量a的偏移量为0,所以a占1个字节。

  • 对于成员变量b,min(4,sizeof(char))的值为1,所以偏移量为1的倍数,所以b也占一个字节且不补全。
  • 对于成员变量c,min(4,sizeof(int))的值为4,所以偏移量为4的倍数,也就是说c只能从4,8,16开始放,因此在b后面要空开两个字节,再放成员变量c。
  • 目前为止,abc加起来总共占了8个字节,然后要确定sizeof(struct Node),还要知道min(4,sizeof(int))的值为4,所以无需再补全。
  • 最后sizeof(struct Node)的值就为8。

#include<stdio.h>
#pragma pack(4)

struct Node{
    char a;
    int c;
    char b;
};
int main(void){
    printf("%d",sizeof(struct Node));
    return 0;
} 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!