大家好,欢迎来到IT知识分享网。
1.1 为什么要对齐
在编译器上已经自动对齐,为什么还需要关注对齐。
不对齐会浪费空间,并且影响可移植性和性能:例如MIPS下如果跨4字节会导致主存读写需要多次读写并且多段拼接,影响效率,有的硬件不支持非对齐访问,有的硬件部分支持。
X86硬件支持;ARM支持普通指令非对齐访问,但是SIMD指令必须要求对齐。mips的硬件不支持,但是靠软件拼接,影响性能会告警。
1.2 基础类型的对齐规则
对于char型数据,其自身对齐值为1,对于short型为2,对于int,float类型,其自身对齐值为4,对于double型,其自身对齐值为8,单位字节。
结构体或者类的自身对齐值:其成员中自身对齐值最大的那个值。
指定对齐值:#pragma pack (value)时的强制指定对齐值value。结束使用#pragma pack()
数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中小的那个值。
使用代码可以验证:
void baseSizeof()
{
printf(“sizeof(char)=%ld\n”, sizeof(char));
printf(“sizeof(short)=%ld\n”, sizeof(short));
printf(“sizeof(int)=%ld\n”, sizeof(int));
printf(“sizeof(long)=%ld\n”, sizeof(long));
printf(“sizeof(long long)=%ld\n”, sizeof(long long));
printf(“sizeof(float)=%ld\n”, sizeof(float));
printf(“sizeof(double)=%ld\n”, sizeof(double));
printf(“sizeof(char*)=%ld, sizeof(int*)=%ld, sizeof(float*)=%ld\n”, sizeof(char*), sizeof(int*), sizeof(float*));
}
64位上运行结果:
sizeof(char)=1
sizeof(short)=2
sizeof(int)=4
sizeof(long)=8
sizeof(long long)=8
sizeof(float)=4
sizeof(double)=8
sizeof(char*)=8, sizeof(int*)=8, sizeof(float*)=8
1.3 结构体的对齐规则
结构体的每个成员的开始地址,必须是类型对应整数倍,可以是0。
结构体的开始地址是所有成员类型最大的整数倍,才可以满足结构体数组的要求
1.4 编译器自动对齐
编译器会自动填充padding做对齐处理,同时要求开发人员把结构体长度最大的成员尽量在前面,否则浪费空间。
1.5 浪费空间的验证
样例代码
#include <stdio.h>
typedef struct stu_t{
long j;
char c1;
char c2;
}stu;
typedef struct stu2_t{
char c1;
long j;
char c2;
}stu2;
#pragma pack(1)
typedef struct stu3_t{
char c1;
long j;
char c2;
}stu3;
#pragma pack()
int main()
{
stu st;
st.j = 1;
st.c1 = ‘1’;
st.c2 = ‘2’;
stu * p = &st;
p++;
printf(“sizeof(stu)=%ld,st++=%p\n”, sizeof(stu), p);
stu2 st2;
st2.c1 = ‘2’;
st2.j = 1;
st2.c2 =’3′;
stu2 * p2 = &st2;
p2++;
printf(“sizeof(stu2)=%ld,st2++=%p\n”, sizeof(stu2), p2);
printf(“sizeof(stu2)=%ld,st2.j=%ld\n”, sizeof(stu2), st2.j);
stu3 st3;
char * p3 = (char *)&st3;
p3++;
int * p4 = (int*)p3;
*p4= 0x;
printf(“sizeof(stu3)=%ld,st3.j=%ld\n”, sizeof(stu3), st3.j);
printf(“in align, sizeof(stu)=%ld,sizeof(stu2)=%ld\n”, sizeof(stu), sizeof(stu2));
printf(“st2.c1=%d\n”,st2.c1);
printf(“st.c1=%d\n”,st.c1);
return 0;
}
编译指令:
gcc -o align -g align.c
#打印空间大小,看到浪费8字节
in align, sizeof(stu)=16,sizeof(stu2)=24
编译器得到汇编代码
参考https://www.cnblogs.com/orlion/p/5817523.html,分析st2
objdump -S align > align.s
虽然栈是从高地址向低地址增长的,但结构体成员也是从低地址向高地址排列的,这一点和数组类似。与数组不同的是结构体成员之间不是一个紧挨一个排列的,中间有空隙,称为填充(Padding),不仅如此,在这个结构体的末尾也有字节的填充
对照画图:st2总长度0x18,即24字节,分别如下
运行可以通过gdb验证
#详细字段的定位,参见gdb
st的j占用8字节
st的c1占用1字节
st的c2占用1字节
st整个结构体被补齐6个字节(16进制,40-38=8个字节,减去c1和c2)
st整个占用:8+(1+1+6)=16字节
st2的c1占用1字节,被补齐8字节
st2的j占用8字节(16进制下,50-48=8)
st2的c2占用1字节
st2整个结构体补齐7个,满足8的倍数
st2整个占用:8+8+(1+7)=24字节
1.6 影响主存读写
待确认验证方式(后继补充)
1.7 影响cache读写
待确认验证方式(后继补充)
1.8 建议规则
第一个属性是结构体长度最大的类型,减少空间浪费。
例如下图1:(1+7)+8+(1+7)=24字节
图2: 8 + 1+(1+6)=16字节
1.9 编译告警,intel运行正常
参见:https://blog.csdn.net/jasonchen_gbd/article/details/?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-1–blog-.pc_relevant_vip_default&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-1–blog-.pc_relevant_vip_default&utm_relevant_index=1
原始代码:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h> /* memcpy */
struct pack_info {
unsigned char sno;
unsigned int len;
} __attribute__((packed));
void sigbus_handler(int sno)
{
printf(“signal %d captured\n”, sno);
exit(1);
}
int main(int argc, char *argv[])
{
signal(SIGBUS, sigbus_handler);
struct pack_info * mem_cos = (struct pack_info *)malloc(sizeof(struct pack_info));
if (!mem_cos)
return 1;
unsigned int * cy_len = &mem_cos->len;
mem_cos->sno = 0x12;
mem_cos->len = 0x;
/* 1. 给成员变量赋值 */
mem_cos->len = 0xaabbccdd;
/* 2. 给指针cy_len的值赋值 */
*cy_len = 0xaabbccdd;
/* 3. 通过memcpy赋值 */
unsigned int cy_len_i = 0xaabbccdd;
memcpy(cy_len, &cy_len_i, 4);
printf(“sno = %#x, len = %#x\n”, mem_cos->sno, mem_cos->len);
free(mem_cos);
return 0;
}
intel下编译告警address-of-packed-member
@LAPTOP-E86I4D9D:~/workspace/align$ gcc -o align3 align3.c -g
align3.c: In function ‘main’:
align3.c:25:26: warning: taking address of packed member of ‘struct pack_info’ may result in an unaligned pointer value [-Waddress-of-packed-member]
25 | unsigned int * cy_len = &mem_cos->len;
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/95469.html