服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - C语言结构体中内存对齐的问题理解

C语言结构体中内存对齐的问题理解

2022-09-16 14:15诚挚的乔治 C/C++

内存对齐”应该是编译器的“管辖范围”。编译器为程序中的每个“数据单元”安排在适当的位置上。但是C语言的一个特点就是太灵活,太强大,它允许你干预“内存对齐”。如果你想了解更加底层的秘密,“内存对齐”对你就不

前言

学C的同学应该知道~

想精通C语言就不得不面对—指针与内存

续上次指针的进阶,这一章我来聊一聊C语言内存对齐的问题

学习结构体的你有没有注意过结构体向系统申请的内存为多少呢的

思考

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include<stdio.h>
typedef struct s1
{
    char a;
    char b;
    int c;
}s1;
typedef struct s2
{
    char a;
    int c;
    char b;
}s2;
int main()
{
 
    //内存对齐的现象
    printf("%d\n", sizeof(s1));
    printf("%d\n", sizeof(s2));
    return 0;
}

很显然这一段代码就是计算s1与s2向系统申请的内存大小

我:两个char类型各为一,再加上应该int类型的四,结果就是六

诚挚的乔治:你说的对,但不完全对,在结构体中会出现内存对齐的现象,不信?看结果

C语言结构体中内存对齐的问题理解

别慌,看到文章的最后,你(也许)就会恍然大悟

在结构体中,内存不是成员的大小之和

结构体在内存中开辟空间时内存对齐的规则

1.结构体中的第一个成员存放在这个结构体的零偏移处,故第一个成员char类型的的偏移量为零

2.从第二个成员开始,每个成员都要对齐到成员对齐数的整数倍

(对齐数--成员自身大小与默认对齐数的最小值的整数倍,如果自身大小是四,默认对齐数是八,最终的对齐数就是四的倍数),一般情况下默认对齐数就是八。

3.结构体的总大小必须是最大对齐数的整数倍 。

(最大对齐数就是每个成员对齐数中的最大值)

4.如果结构体中嵌套结构体的情况下,嵌套的结构体就对齐到自己成员对齐数的最大对齐数的整数倍处,结构体的总大小就是最大对齐数(含嵌套的结构体成员)的整数倍。

 下面其中的一个结构体进行分析:

 先向大家介绍一下本章的配角—offsetof

C语言结构体中内存对齐的问题理解

offsetof的返回值就是距离这个结构体(自定义类型)起始位置的值

参数就是结构体的名称和结构体成员的名称。

C语言结构体中内存对齐的问题理解

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<stddef.h>
#include<stdio.h>
typedef struct s
{
    char a;
    int b;
    char c;
}s;
int main()
{
    //offsetof-是指偏移量
    printf("%d\n", offsetof(s,a));
    printf("%d\n", offsetof(s,b));
    printf("%d\n", offsetof(s,c));
    return 0;
}

C语言结构体中内存对齐的问题理解

char a; //因为char a是结构体第一个成员,所以偏移量就是零

int b;   //自身大小:  4    默认对齐数:8   对齐数:4的倍数即可,所以偏移量就是四

char c; // 自身大小: 1    默认对齐数:8   对齐数:1的倍数即可,所以偏移量就是八

又因为最终的结构体大小是成员最大对齐数的倍数,也就是四的倍数,所以最终的结构体的大小应该就是十二。

C语言结构体中内存对齐的问题理解

到这里是不是有一定的思路了,别急,再来一道试试吧

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include<stddef.h>
#include<stdio.h>
typedef struct s
{
    double a;
    char b;
    int  c;
}s;
int main()
{
    //offsetof-是指偏移量
    printf("%d\n", offsetof(s,a));
    printf("%d\n", offsetof(s,b));
    printf("%d\n", offsetof(s,c));
    printf("%d", sizeof(s));
    return 0;
}

结果如下:

C语言结构体中内存对齐的问题理解

是不是跟你想的一样呢?

同样的,用一样的方法进行解释

double a;     //因为double a是结构体第一个成员,所以偏移量就是零

char b;     //自身大小:1    默认对齐数:8  对齐数:1的倍数即可,所以偏移量就是八

int  c;        //自身大小:4    默认对齐数:8   对齐数:4的倍数即可,所以偏移量就是十二

最终结构体的大小就是四的整数倍十六

C语言结构体中内存对齐的问题理解

下面给应该结构体嵌套结构体的例子

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include<stdio.h>
#include<stddef.h>
typedef struct s1
{
    char i;
    char j;
    int k;
}s1;
typedef struct s2
{
    char a;
    int c;
    s1;
}s2;
int main()
{
 
    printf("%d\n", offsetof(s2, a));
    printf("%d\n", offsetof(s2, c));
    printf("%d", sizeof(s2));
    return 0;
}

C语言结构体中内存对齐的问题理解

C语言结构体中内存对齐的问题理解

我相信此时的你一定会计算结构体想系统申请的大小,以及内存对齐是咋回事

其实,内存对齐也就那么回事儿~

为什么存在内存对齐

知道怎样计算后,你是否和我一样思考

为什么内存的申请不能想main函数中的内存申请一样,要多少就申请相应大小的空间,这样既省内存,也不用考虑这么多。

1.平台的原因

所谓平台原因就是与硬件有关,硬件不能访问内存中的每一个空间,换句话说,就是按一定的规律进行访问,这样内存对齐就起到了很好的作用

2.性能的原因

数据结构(尤其是栈),应该尽可能的在自然边界上对齐

因为我们的CPU访问空间,就是一次性按四个字节的空间来访问,内存对齐在一定的时候避免了访问一次的空间进行了二次访问

如下访问应该int类型内存对齐后只需要访问一次

C语言结构体中内存对齐的问题理解

C语言结构体中内存对齐的问题理解

总的来说内存对齐就是拿空间换取时间

当然,我们可以实现内存对齐之上,也可以进行省一定空间

就想博客开头一道题,一模一样的代码,最终的结构体的大小却不一样,这种就是优化版的结构体

这里给一个小的技巧,就是把空间小的成员尽量放在一起

到此这篇关于C语言结构体中内存对齐的问题理解的文章就介绍到这了,更多相关C语言 内存对齐内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/m0_64332179/article/details/122682708

延伸 · 阅读

精彩推荐
  • C/C++C语言:传值与传址交换整数

    C语言:传值与传址交换整数

    这篇文章主要给大家介绍了关于C语言中传值与传址之间交换整数的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用C语言具有一定的参...

    rampant boy3562021-12-13
  • C/C++C语言中结构体struct编写的一些要点解析

    C语言中结构体struct编写的一些要点解析

    这篇文章主要介绍了C语言中结构体struct编写的一些要点解析,谈到了结构体的声明和指针指向等重要知识点,需要的朋友可以参考下...

    whuslei9852021-03-30
  • C/C++C++如何删除map容器中指定值的元素详解

    C++如何删除map容器中指定值的元素详解

    map容器是C++ STL中的重要一员,删除map容器中value为指定元素的问题是我们经常与遇到的一个问题,下面这篇文章主要给大家介绍了关于利用C++如何删除map容...

    vfhky9772021-05-18
  • C/C++C++中的函数汇总

    C++中的函数汇总

    这篇文章主要介绍了 C++中的函数汇总的相关资料,需要的朋友可以参考下...

    航行的帆船11952021-05-30
  • C/C++算法详解之分支限界法的具体实现

    算法详解之分支限界法的具体实现

    这篇文章主要介绍了算法详解之分支限界法的具体实现,需要的朋友可以参考下...

    C语言教程网6162021-01-15
  • C/C++浅谈C++中对象的复制与对象之间的相互赋值

    浅谈C++中对象的复制与对象之间的相互赋值

    这篇文章主要介绍了浅谈C++中对象的复制与对象之间的相互赋值,是C语言入门学习中的基础知识,需要的朋友可以参考下...

    C++教程网5052021-03-13
  • C/C++详解c++ 继承

    详解c++ 继承

    这篇文章主要介绍了c++ 继承的相关资料,文中讲解非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下...

    菜鸟教程4782021-09-16
  • C/C++C++内存管理详细解析

    C++内存管理详细解析

    这篇文章主要给大家分享的是C++内存管理的详细内容学习,下面文章围绕C++内存管理的相关资料展开具体学习内容,需要的朋友可以参考一下,希望对你有所...

    妙妙园9892022-02-28