这一次要介绍的是一个gcc编译参数:
__attribute__((__aligned__(n)))
这里,我们将不讨论结构体内部的对齐问题。
我们将分为三个部分介绍这个编译参数——针对变量
、类型
和结构体
。
首先我们看一个简单的例子:
#include <stdio.h>
int main(void)
{
int i __attribute__((__aligned__(64))) = 10;
printf("%lx %lu\n", (unsigned long)&i, sizeof(i));
return 0;
}
通过编译后,执行这个程序,结果如下:
7fffadbc43c0 4
可以看到,变量i的内存地址的后6位为0。而变量i占用的内存大小为4个字节。
这说明,对齐使得i的内存起始地址向64字节对齐了,但不影响其内存大小。
何为针对类型呢?我们来看下面这个例子:
#include <stdio.h>
typedef int Int __attribute__((__aligned__(64)));
int main(void)
{
Int i = 10;
printf("%lx %lu\n", (unsigned long)&i, sizeof(i));
return 0;
}
编译后运行,发现与上例结果相似,变量i的起始地址为64字节对齐。
那么如果我们修改一下,变为如下代码呢?
#include <stdio.h>
typedef int Int __attribute__((__aligned__(64)));
int main(void)
{
Int i[2] = {1, 10};
printf("%lx %lu\n", (unsigned long)&i, sizeof(i));
return 0;
}
此时,编译代码就会报错,遇到类似如下报错提示:
错误:数组元素的对齐边界比元素大小还要大
这话什么意思呢?
简单来说,数组i的每个元素要向64字节对齐,而每个数组元素所占内存大小为4字节,那么就会发现,元素之间有空隙。这就是这个报错的意思,数组元素不连续了。
最后,我们来看看结构体的一些行为是怎样的。示例如下:
#include <stdio.h>
struct test {
long a;
long b;
long c;
long d;
long e;
long f;
long g;
long h;
long i;
} __attribute__((__aligned__(64)));
int main(void)
{
struct test t;
printf("%lx %lu\n", (unsigned long)&t, sizeof(t));
return 0;
}
编译代码,然后运行,结果如下:
7ffe525cce40 128
可以看到,结构体变量t内存起始地址依旧保持了64字节对齐,且结构体变量的大小也变为64字节的整数倍了。
此时假设我们将代码中t定义的语句改为:
struct test t[2];
依旧可以通过编译。
可见,空隙问题对于结构体是不存在影响的,因为编译器只需要调整结构体大小就可以将空隙自动填平了。