高级C__attribute__((aligned(n))) 与 #pragma(pack(n))的区别
Posted 从善若水
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了高级C__attribute__((aligned(n))) 与 #pragma(pack(n))的区别相关的知识,希望对你有一定的参考价值。
文章目录
本人就职于国际知名终端厂商,负责modem芯片研发。
在5G早期负责终端数据业务层、核心网相关的开发工作,目前牵头6G算力网络技术标准研究。
博客内容主要围绕:
5G协议讲解
算力网络讲解(云计算,边缘计算,端计算)
高级C语言讲解
Rust语言讲解
attribute((aligned(n))) 与 #pragma(pack(n))的区别
先看个例题一:
#pragma pack(push,2)
typedef struct test{
char a;
double b;
char c;
int d;
} __attribute__ ((aligned (32))) test ;
#pragma pack(pop)
问:计算 sizeof(test) ?
答:32
再看例题二:
#pragma pack(push,4)
typedef struct test{
char a;
double b;
char c;
int d;
} __attribute__ ((aligned (2))) test ;
#pragma pack(pop)
问:计算 sizeof(test) ?
答:20
再看例题三:
typedef struct subtest{
char a;
double b;
char c;
int d;
}subtest;
#pragma pack(push,2)
typedef struct test{
char a;
subtest b;
} __attribute__ ((aligned (4))) test ;
#pragma pack(pop)
问:计算 sizeof(test) ?
答:28
好,不折磨大家了,我们进入正题!!!
一、正确理解__attribute__((aligned(x)))
attribute((aligned(x)))定义的是最小对齐边界,它可以用来修饰structure也可以用来修饰变量或者structure成员变量,它只能增加 structure、变量或者structure成员变量的对齐值(GCC手册说在修饰 typedef 类型时可以增加或减少对齐值)。
二、正确理解 #pragma(pack(n))
#pragma(pack(n))定义的是最大对齐边界,它可以用来修饰structure也可以用来修饰structure成员变量,它可以增加/减少 structure或者structure成员变量的对齐值。
三、详解开篇例题
首先我们要明确在 code顺序上 ,上述例题的 #pragma(pack(n)) 先生效,然后才是 __attribute__((aligned(x)))生效。
3.1 例题一解答
#pragma pack(push,2)
typedef struct test{
char a;
double b;
char c;
int d;
} __attribute__ ((aligned (32))) test ;
#pragma pack(pop)
① #pragma pack(push,2) 将编译器的最大对齐边界设置为 2
② 以 2 为最大对齐边界后,test 的内存对齐情况(先不考虑 aligned 属性):
typedef struct test{
char a; // 1B
double b; //因为最大对齐是2,所以只需要满足2的倍数,不需要满足8的倍数
//填充 1B ,b 本身占据 8B
char c; //对齐时我们要选择最小的对齐值,对于 c最小的对齐值是1(不是2)
//无填充,自身占据 1B
int d; //对齐值为2,故填充 1B,自身占据 4B
} test ; //整个结构体对齐值为 2(不是8,因为已经设置了最大对齐值是2)
// (1B) + (1B+8B) + (1B) + (1B+4B) + 0B(已经满足2的倍数,无需对结构体进行填充)
也就是说当前(不考虑 aligned 属性)时,test 类型占据 16B,最大对齐值 2 。
③ 最后来看 aligned 属性,我们前面说了,aligned 属性设置的是最小对齐值,也就是说当前类型或变量的对齐值要大于或等于aligned 属性设置的对齐值,所以编译器重新设置 test类型的对齐值为32,则test struct需要填充16B。
✔结果就是32B 。
3.2 例题二解答
例题二不再赘述,对应于 test类型的对齐值,大于 aligned 属性设置的最小对齐值的情况,这种情况下可以忽略aligned 属性。
✔结果就是20B 。
3.3 例题三解答
① test 的内存对齐情况(先不考虑 aligned 属性)
typedef struct subtest{
char a;
double b;
char c;
int d;
}subtest;
#pragma pack(push,2)
typedef struct test{
char a; // 1B
subtest b; //对于结构体subtest,原本以 8B做为对齐值
//但这里设置了最大对齐值2,所以 填充1B,自身占据 24B
} test ; // (1B) + (1B+24B) + 0B(已经是2的倍数,不需要再填充)
#pragma pack(pop)
② 最后来看 aligned 属性,设置的最小对齐值4 > 2,所以 test 结构体需要填充 2B,以构成4的倍数。
✔结果就是28B 。
四、注意__attribute__ ((aligned (n)))的位置
代码一:
typedef struct test{
char a;
double b;
char c;
int d;
} __attribute__ ((aligned (16))) test ;
代码二:
typedef struct test{
char a;
double b;
char c;
int d;
} test __attribute__ ((aligned (16)));
代码一修饰的是 struct test类型
代码二修饰的是 test类型
有什么区别呢? 下面的code和输出结果,不再解释,自悟!
代码一:
#include <stdio.h>
typedef struct test{
char a;
double b;
char c;
int d;
} __attribute__ ((aligned (16))) test ;
int main() {
test a ;
printf("%d\\n",sizeof(test));
printf("%f\\n",(unsigned long long)&a/16.);
return 0;
}
代码二:
#include <stdio.h>
typedef struct test{
char a;
double b;
char c;
int d;
} test __attribute__ ((aligned (16)));
int main() {
test a ;
printf("%d\\n",sizeof(test));
printf("%f\\n",(unsigned long long)&a/16.);
return 0;
}
以上是关于高级C__attribute__((aligned(n))) 与 #pragma(pack(n))的区别的主要内容,如果未能解决你的问题,请参考以下文章
GNU C字节对齐__attribute__((aligned(n))) #pragma pack(n)