补充1:字节对齐

补充1:字节对齐align3 c In function main align3 c 25 26 warning taking address of packed member of struct pack info may result i

大家好,欢迎来到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:字节对齐

结构体的开始地址是所有成员类型最大的整数倍,才可以满足结构体数组的要求

补充1:字节对齐

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),不仅如此,在这个结构体的末尾也有字节的填充

补充1:字节对齐

对照画图:st2总长度0x18,即24字节,分别如下

补充1:字节对齐

运行可以通过gdb验证

#详细字段的定位,参见gdb

补充1:字节对齐

st的j占用8字节

st的c1占用1字节

st的c2占用1字节

st整个结构体被补齐6个字节(16进制,40-38=8个字节,减去c1和c2)

st整个占用:8+(1+1+6)=16字节

补充1:字节对齐

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:字节对齐

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

(0)

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信