数据对齐

什么是数据对齐?

一般情况下,当我们定义一个变量,编译器会按照默认的地址对齐方式,来给该变量分配一个存储空间地址。如果该变量是一个 int 型数据,那么编译器就会按4字节或4字节的整数倍对齐;如果该变量是一个 short 型数据,那么编译器就会按2字节或2字节的整数倍边界对齐;如果是一个 char 类型的变量,那么编译器就会按照1字节对齐。

#include <stdio.h>

int a = 1;
int b = 2;
char c1 = 3;
char c2 = 4;
int main(void) {
	printf("a: %p\n",&a);
	printf("b: %p\n",&b);
	printf("c1:%p\n",&c1);
	printf("c2:%p\n",&c2);
	return 0;
}

在上面的程序中,我们分别定义2个 int 型变量,2个 char 型变量,然后分别打印它们的地址,运行结果如下。

a:  00402000
b:  00402004
c1: 00402008
c2: 00402009

通过运行结果我们可以看到,对于 int 型数据,其在内存中的地址都是以4字节或4字节整数倍对齐的。而 char 类型的数据,其在内存中是以1字节对齐的。变量 c2 就直接分配到了 c1 变量的下一个存储单元,不用像 int 数据那样考虑4字节对齐。接下来,我们修改一下程序,指定变量 c2 按4字节对齐。

#include <stdio.h>

int a = 1;
int b = 2;
char c1 = 3;
char c2 __attribute__((aligned(4))) = 4;
int main(void) {
    printf("a: %p\n",&a);
    printf("b: %p\n",&b);
    printf("c1:%p\n",&c1);
    printf("c2:%p\n",&c2);
    return 0;
}

运行结果如下。

a:  00402000
b:  00402004
c1: 00402008
c2: 0040200C

通过运行结果可以看到,字符变量 c2 由于使用 aligned 属性声明按照4字节边界对齐,所以编译器不可能再给其分配 0x00402009 这个地址,因为这个地址不是4字节对齐的。编译器空出3个字节单元,直接从 0x0040200C 这个地址上给变量 c2 分配存储空间。

为什么要数据对齐?

  1. 通过 aligned 这个属性声明,我们虽然可以显式指定变量的地址对齐方式,但是也会因边界对齐造成一定的内存空洞,浪费一定的内存空间。比如在上面这个程序中,0x00402009~0x0040200b 这三个地址空间的存储单元就没有被使用。
  2. 既然地址对齐会造成一定的内存空洞,那我们为什么还要按照这种对齐方式去存储数据呢?
    一个主要原因就是,这种对齐设置可以简化 CPU 和内存 RAM 之间的接口和硬件设计。比如一个32位的计算机系统,CPU 读取内存时,硬件设计上可能只支持4字节或4字节倍数对齐的地址访问,CPU 每次往内存 RAM 读写数据时,一个周期可以读写4个字节。如果我们把一个数据放在4字节对齐的地址上,那么CPU一次就可以把数据读写完毕;如果我们把一个 int 型数据放在一个非4字节对齐的地址上,那 CPU 就要分2次才能把这个4字节大小的数据读写完毕。
  3. 为了配合计算机的硬件设计,编译器在编译程序时,对于一些基本数据类型,比如 int、char、short、float 等,会按照其数据类型的大小进行地址对齐,按照这种地址对齐方式分配的存储地址,CPU一次就可以读写完毕。虽然边界对齐会造成一些内存空洞,浪费一些内存单元,但是在硬件上的设计却大大简化了。这也是编译器给我们定义的变量分配地址时,不同类型变量按不同字节数地址对齐的原因。除了 int、char、short、float 这些基本类型数据,对于一些复合类型数据,也要满足地址对齐要求。
  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值