浅谈C语言对齐

在码哥以前的文章中也有提及过对齐,但这一次要介绍的是一个gcc编译参数:

__attribute__((__aligned__(n)))

这里,我们将不讨论结构体内部的对齐问题。

我们将分为三个部分介绍这个编译参数——针对变量、类型结构体

针对变量

首先我们看一个简单的例子:

<code>#include <stdio.h>

int main(void)
{
int i __attribute__((__aligned__(64))) = 10;
printf("%lx %lu\\n", (unsigned long)&i, sizeof(i));
return 0;
}/<stdio.h>/<code>

通过编译后,执行这个程序,结果如下:

<code>7fffadbc43c0 4/<code>

可以看到,变量i的内存地址的后6位为0。而变量i占用的内存大小为4个字节。

这说明,对齐使得i的内存起始地址向64字节对齐了,但不影响其内存大小。

针对类型

何为针对类型呢?我们来看下面这个例子:

<code>#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;
}/<stdio.h>/<code>

编译后运行,发现与上例结果相似,变量i的起始地址为64字节对齐。

那么如果我们修改一下,变为如下代码呢?

<code>#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;
}/<stdio.h>/<code>

此时,编译代码就会报错,遇到类似如下报错提示:

<code>错误:数组元素的对齐边界比元素大小还要大/<code>

这话什么意思呢?

简单来说,数组i的每个元素要向64字节对齐,而每个数组元素所占内存大小为4字节,那么就会发现,元素之间有空隙。这就是这个报错的意思,数组元素不连续了。

针对结构体

最后,我们来看看结构体的一些行为是怎样的。示例如下:

<code>#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;
}/<stdio.h>/<code>

编译代码,然后运行,结果如下:

<code>7ffe525cce40 128/<code>

可以看到,结构体变量t内存起始地址依旧保持了64字节对齐,且结构体变量的大小也变为64字节的整数倍了。

此时假设我们将代码中t定义的语句改为:

<code>struct test t[2];/<code>

依旧可以通过编译。

可见,空隙问题对于结构体是不存在影响的,因为编译器只需要调整结构体大小就可以将空隙自动填平了。


分享到:


相關文章: