c语言结构体对齐6,C语言结构体之内存对齐

C语言结构体之内存对齐

1、什么是内存对齐

首先看一个例子,下面有一个结构体:

struct structTest1

{

char c1;

short s;

char c2;

int i;

};

假设这个结构体成员在内存中是紧凑排列的,那么c1的存储地址就是0,s的存储地址是1-2,c2的存储地址是3,i的存储地址是4-7,c1的地址是0000000000000000,s的地址是0000000000000001,c2的地址是0000000000000003,i的地址是0000000000000004,整个结构体所占内存是8。但是写一个程序输出一下,则会得到不同的结果。

#include

struct structTest1

{

char c1;

short s;

char c2;

int i;

};

int main()

{

struct structTest1 s1;

printf("sizeof(s1): %d\n", sizeof(s1));

printf("c1:%p\ns :%p\nc2:%p\ni :%p\n",\

(unsigned int)(void*)&s1.c1 - (unsigned int)(void*)&s1,\

(unsigned int)(void*)&s1.s - (unsigned int)(void*)&s1,\

(unsigned int)(void*)&s1.c2 - (unsigned int)(void*)&s1,\

(unsigned int)(void*)&s1.i - (unsigned int)(void*)&s1);

return 0;

}

833e0241dbc3b3a5c43cd6b3249dcd4b.png

程序的输出结果与我们预测的结果不一致,这就是因为内存对齐导致的。

内存对齐就是,按照成员的声明顺序,依次安排内存,其偏移量为最大成员大小的整数倍,最后结构体的大小为最大成员的整数倍。

2、为什么会有内存对齐

因为访问未对齐的内存,处理器需要做两次内存访问,然而对齐的内存访问仅需要一次访问。缺省情况下,编译器默认将结构、栈中的成员数据进行内存对齐。编译器将未对齐的成员往后移,将每一个成员都对齐到自然边界上,从而也导致了整个结构体的尺寸变大。尽管会牺牲一点空间(成员间有部分内存空闲),但提高了性能。

3、如何避免内存对齐的影响

一个小技巧就是将上面的结构体写成下面的形式:

struct structTest1

{

char c1;

short s;

char c2;

int i;

};

这样一来,每个成员都对齐在其自然边界上,从而避免了编译器自动对齐。

#include

struct structTest1

{

char c1;

char c2;

short s;

int i;

};

int main()

{

struct structTest1 s1;

printf("sizeof(s1): %d\n", sizeof(s1));

printf("c1:%p\nc2:%p\ns :%p\ni :%p\n",\

(unsigned int)(void*)&s1.c1 - (unsigned int)(void*)&s1,\

(unsigned int)(void*)&s1.c2 - (unsigned int)(void*)&s1,\

(unsigned int)(void*)&s1.s - (unsigned int)(void*)&s1,\

(unsigned int)(void*)&s1.i - (unsigned int)(void*)&s1);

return 0;

}

f8757fa294951cf9fb5c817f9e6b2830.png

除此之外我们还可以利用#pragma pack()来改变编译器的默认对齐方式

使用指令#pragma pack (n),编译器将按照 n 个字节对齐。

使用指令#pragma pack (),编译器将取消自定义字节对齐方式。

在#pragma pack (n)和#pragma pack ()之间的代码按 n 个字节对齐。

当n=1时:

#include

#pragma pack(1)

struct TestStruct1

{

char a;

long b;

};

struct TestStruct2

{

char c;

struct TestStruct1 d;

long long e;

};

#pragma pack()

int main()

{

printf("sizef(TestStruct2): %d\n", sizeof(struct TestStruct2));

return 0;

}

922e3478288427c10ebd72ebc51b3542.png

当n=2时

#include

#pragma pack(2)

struct TestStruct1

{

char a;

long b;

};

struct TestStruct2

{

char c;

struct TestStruct1 d;

long long e;

};

#pragma pack()

int main()

{

printf("sizef(TestStruct2): %d\n", sizeof(struct TestStruct2));

return 0;

}

97dc5af3a48a3887ea3a91d7adcd423c.png

当n=4时

#include

#pragma pack(4)

struct TestStruct1

{

char a;

long b;

};

struct TestStruct2

{

char c;

struct TestStruct1 d;

long long e;

};

#pragma pack()

int main()

{

printf("sizef(TestStruct2): %d\n", sizeof(struct TestStruct2));

return 0;

}

6afea838b5f73d6b31771b5c109bab49.png

当n=8时

#include

#pragma pack(8)

struct TestStruct1

{

char a;

long b;

};

struct TestStruct2

{

char c;

struct TestStruct1 d;

long long e;

};

#pragma pack()

int main()

{

printf("sizef(TestStruct2): %d\n", sizeof(struct TestStruct2));

return 0;

}

bf5b8225c6734409d782a5954cfa5eac.png

标签:struct,int,s1,unsigned,C语言,体之,对齐,void

来源: https://www.cnblogs.com/xiaohzd/p/13543848.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值