概述
在性能要求比较高的场景下,经常会用到字节对齐,我们可以通过gcc的__attribute__来设置struct的字节对齐,比较常用的就是aligned和packet,本文主要介绍这两种设置字节对齐的用法。
1. aligned - 设置变量对齐
aligned的功能就是设置变量按照指定的字节进行内存对齐,对齐的字节数必须是2的指数,再看一个使用的例子:
// file: test.c
// gcc test.c -o test
#include <stdint.h>
#include <stdio.h>
struct Test1 {
int64_t a;
int8_t b;
int32_t c;
int8_t d;
};
struct Test2 {
int64_t a;
int8_t b __attribute__((aligned(16)));
int32_t c;
int8_t d;
};
struct Test3 {
int64_t a;
int8_t b;
int32_t c;
int8_t d;
} __attribute__((aligned(16)));
int main() {
struct Test1 t1;
struct Test2 t2;
struct Test3 t3;
printf("sizeof(t1) = %dn", sizeof(t1));
printf("sizeof(t2) = %dn", sizeof(t2));
printf("sizeof(t3) = %dn", sizeof(t3));
printf("t1 &a = 0x%p, &b = 0x%p, &c= 0x%p &d = 0x%pn", &t1.a, &t1.b, &t1.c, &t1.d);
printf("t2 &a = 0x%p, &b = 0x%p, &c= 0x%p &d = 0x%pn", &t2.a, &t2.b, &t2.c, &t2.d);
printf("t3 &a = 0x%p, &b = 0x%p, &c= 0x%p &d = 0x%pn", &t3.a, &t3.b, &t3.c, &t3.d);
}
输出是:
$./test
sizeof(t1) = 24
sizeof(t2) = 32
sizeof(t3) = 32
t1 &a = 0x0x7ffe7bb381b0, &b = 0x0x7ffe7bb381b8, &c= 0x0x7ffe7bb381bc &d = 0x0x7ffe7bb381c0
t2 &a = 0x0x7ffe7bb38190, &b = 0x0x7ffe7bb381a0, &c= 0x0x7ffe7bb381a4 &d = 0x0x7ffe7bb381a8
t3 &a = 0x0x7ffe7bb38170, &b = 0x0x7ffe7bb38178, &c= 0x0x7ffe7bb3817c &d = 0x0x7ffe7bb38180
test1为什么是24字节?因为gcc编译程序的时候会遵循两个准则:
- 结构体变量中成员的偏移量必须是成员大小的整数倍;
- 结构体总大小必须是所有成员大小的整数倍,也就是说是所有成员大小的公倍数;
- 结构体的总大小为结构体对齐字节数大小的整数倍。
t2、t3都是32字节,那么他们的内存布局是一样的吗?其实是不一样的,t1、t2、t3的内存布局如下图所示(深色区域为padding):
在__attribute__变量属性中,还有一个“warn_if_not_aligned”用来检查结构体对齐,它的用法如下:
struct foo {
int a;
int b;
} __attribute__ ((warn_if_not_aligned (16)));
上面的代码在编译的时候会报“warning: ‘warn_if_not_aligned’ attribute directive ignored [-Wattributes]”警告错误。
字节对齐实际上做的是偏移量对齐以及长度对齐,对齐会浪费内存空间,那为什么还要做字节对齐呢?原因是为了提高内存系统性能,机器从内存中读取数据时,是按照一定字节(cache_line一般是64B)来获取的,如果不对齐的话,就可能增加读取的次数,降低性能。一般在对性能有极致要求的程序中,会特别关心字节对齐。
2. packed - 设置变量按照1字节对齐
用packed标识结构体,表示的是其成员采用紧凑模式排布,不允许有字节填充,经常用在序列化场景下,如下:
// file: test_packed.c
// gcc test_packed.c -o test_packed
#include <stdio.h>
#include <stdint.h>
struct Test1 {
int64_t a;
int8_t b;
int32_t c;
int8_t d;
} __attribute__ ((packed));
void main() {
printf("sizeof(Test1) = %dn", sizeof(struct Test1));
}
结果如下:
$./test_packed
sizeof(Test1) = 14
3. 参考文档
- https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html#Common-Variable-Attributes
最后
以上就是外向乌龟为你收集整理的gcc之__attribute__字节对齐参数设置的全部内容,希望文章能够帮你解决gcc之__attribute__字节对齐参数设置所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复