c语言|??图解C语言结构体对齐,保姆级教学,建议收藏??
目录
一,结构体的对齐规则
二,默认
三,例题讲解
1,例题一
2,例题二
3,例题三
4,例题四
四,为什么存在内存对齐?
五,修改默认对齐数
六,总结
一,结构体的对齐规则
1,结构体的第一个成员永远放在结构体起始位置偏移为0的地址二,默认
2,结构体从第二个成员,总是放在一个对齐数的整数倍数
对齐数 = 编译器默认的对齐数和变量自身大小的较小值
3,. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
4,如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
Linux没有默认对齐数三,例题讲解 1,例题一
Vs默认对齐数为8
int main()
{
struct S1
{
char c1;
int i;
char c2;
};
printf("%d\n", sizeof(struct S1));
return 0;
}
文章图片
c1在结构体起始位置偏移为0的地址。
i是第二个成员,总是放在一个对齐数的整数倍数,对齐数 = 编译器默认的对齐数和变量自身大小的较小值,i本身为4,Vs默认为8,我们选择从4开始,中间的全部丢弃。
c2本身为一个字节,相比于Vs8来说还是1。
由第三条规则可得:结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
最大对齐数位4,此时我们的内存在8,总大小为9,继续往后延申到达11,总大小为12,是4的整数倍,符合第三条规则。
int main()
{
struct S1
{
char c1;
//字节大小1 Vs为8 所以为1
int i;
//字节大小4 Vs为8 所以为4
char c2;
//字节大小1 Vs为8 所以为1
};
printf("%d\n", sizeof(struct S1));
return 0;
}
文章图片
2,例题二
int main()
{
struct S2
{
char c1;
char c2;
int i;
};
printf("%d\n", sizeof(struct S2));
return 0;
}
文章图片
c1在结构体起始位置偏移为0的地址。
c2是第二个成员,总是放在一个对齐数的整数倍数,对齐数 = 编译器默认的对齐数和变量自身大小的较小值,c2本身为1,Vs默认为8,我们选择从1开始。
i本身为4个字节,相比于Vs8来说还是4。
由第三条规则可得:结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
【c语言|??图解C语言结构体对齐,保姆级教学,建议收藏??】最大对齐数位4,此时我们的内存在7,总大小为8,是4 的整数倍数,符合第三条规则。
int main()
{
struct S2
{
char c1;
//字节大小1 Vs为8 所以为1
char c2;
//字节大小1 Vs为8 所以为1
int i;
//字节大小4 Vs为8 所以为4
};
printf("%d\n", sizeof(struct S2));
return 0;
}
文章图片
3,例题三
int main()
{
struct S3
{
double d;
char c;
int i;
};
printf("%d\n", sizeof(struct S3));
return 0;
}
文章图片
d在结构体起始位置偏移为0的地址。
c是第二个成员,总是放在一个对齐数的整数倍数,对齐数 = 编译器默认的对齐数和变量自身大小的较小值,c2本身为1,Vs默认为8,我们选择从8开始。
i本身为4个字节,相比于Vs8来说还是4。但它必须从12开始,因为此时内存为9,要符合第二条规则。
由第三条规则可得:结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
最大对齐数位4,此时我们的内存在15,总大小为16,是8的整数倍,符合第三条规则。
int main()
{
struct S3
{
double d;
///字节大小8 Vs为8 所以为8
char c;
//字节大小1 Vs为8 所以为1
int i;
//字节大小4 Vs为8 所以为4
};
printf("%d\n", sizeof(struct S3));
return 0;
}
文章图片
4,例题四
int main()
{
struct S3
{
double d;
char c;
int i;
};
printf("%d\n", sizeof(struct S3));
struct S4
{
char c1;
//
struct S3 s3;
double d;
};
printf("%d\n", sizeof(struct S4));
return 0;
}
文章图片
c1在结构体起始位置偏移为0的地址。
由第四条规则可得嵌套的结构体对齐到自己的最大对齐数的整数倍处,S3最大整数倍数为8,所以我们必须从8开始,中间的丢弃,结构体S3本身为16,向后延申16到23.
d为8个字节,从24开始符合规则
由第三条规则可得:结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
最大对齐数位16,此时我们的内存在23,总大小为24,继续延申到31,总大小为32,是16的整数倍,符合第三条规则。
int main()
{
struct S3
{
double d;
//字节大小8 Vs为8 所以为8
char c;
//字节大小1 Vs为8 所以为1
int i;
//字节大小4 Vs为8 所以为4
};
printf("%d\n", sizeof(struct S3));
struct S4
{
char c1;
//字节大小1 Vs为8 所以为1
struct S3 s3;
//字节大小16
double d;
//字节大小8 Vs为8 所以为8
};
printf("%d\n", sizeof(struct S4));
return 0;
}
四,为什么存在内存对齐?
大部分的参考资料都是如是说的:
1. 平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能 在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2. 性能原因: 数据结构(尤其是栈)应该尽可能地在自然边界上对齐。 原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。 总体来说: 结构体的内存对齐是拿空间来换取时间的做法。
那在设计结构体的时候,我们既要满足对齐,又要节省空间,如何做到:
让占用空间小的成员尽量集中在一起。
struct S1
{
char c1;
int i;
char c2;
};
struct S2
{
char c1;
char c2;
int i;
};
S1和S2类型的成员一模一样,但是S1和S2所占空间的大小有了一些区别。五,修改默认对齐数
#include
#pragma pack(8)//设置默认对齐数为8
struct S1
{
char c1;
int i;
char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认
#pragma pack(1)//设置默认对齐数为8
struct S2
{
char c1;
int i;
char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认
int main()
{
//输出的结果是什么?
printf("%d\n", sizeof(struct S1));
printf("%d\n", sizeof(struct S2));
return 0;
}
文章图片
六,总结
既然看到这里了,求赞求评论求收藏,你们的三连是我进步的最大动力。关注我,一起学习进步
推荐阅读
- 【生信技能树】R语言练习题|【生信技能树】R语言练习题 - 中级
- 一起来学习C语言的字符串转换函数
- C语言字符函数中的isalnum()和iscntrl()你都知道吗
- C语言浮点函数中的modf和fmod详解
- C语言中的时间函数clock()和time()你都了解吗
- C语言学习|第十一届蓝桥杯省赛 大学B组 C/C++ 第一场
- 2018-06-13金句系列7(金句结构-改编古现代诗词)
- C语言解方程的根和判断是否是闰年
- C语言的版本比较
- Java内存泄漏分析系列之二(jstack生成的Thread|Java内存泄漏分析系列之二:jstack生成的Thread Dump日志结构解析)