收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人
都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
虚拟内存分为一页页(一般为4K一页)。程序启动时并不需要把所有内容载入到真实的内存中,操作系统和硬件会将虚拟内存和真实内存建立映射。当程序运行时,访问的虚拟内存如果不在真实内存中,就会触发缺页中断,将需要用到的页载入到真实内存中,然后再重新访问。假如真实内存满了,就将太久没使用的页转出到磁盘中。因此,程序就认为自己独立拥有了4G虚拟地址空间,就算真实内存不足4G,也可以运行4G的程序。
2、堆区和栈区的区别
1、申请方式:栈的空间由操作系统自动分配和释放,堆上的空间需要程序员使用malloc\free手动分配和释放。如果不释放会造成内存泄漏。
2、申请大小限制和效率:栈的空间时有限的,在linux中,使用 ulimit -s 指令 ,可以看到看到栈的容量为8M。栈区以先进后出的方式自动分配时连续的内存单元,效率高。
堆的大小受限与系统中有效的虚拟内存大小,系统是用链表来存储空闲的内存块,是不连续的。因此,堆的空间分配比较灵活,但容易产生内存碎片,相对来讲对效率低。
扩展:栈在C语言中的作用
1、用来存储临时变量。包括函数参数和函数内部定义的临时变量。函数调用中和函数调用相关的函数返回地址,函数中的临时变量,寄存器等均保存在栈中,函数调用返回后从栈中恢复寄存器和临时变量等函数运行场景。
简单的说就是局部变量、函数地址和相关参数。当主函数要调用一个函数的时候,要对当前断点进行保存,需要使用栈来实现,首先入栈的是主函数下一条语句的地址,然后是调用函数的参数,一般情况下参数是按照从右向左的顺序入栈,之后是调用函数的局部变量,注意静态变量是存放在全局内存区,是不入栈的;出栈的顺序正好相反,最终栈顶指向主函数下一条语句的地址,主程序又从该地址开始执行。
2、栈是多线程编程的基础,每一个线程都最少有一个自己专属的栈,用来存储本线程运行时各个函数的临时变量,维系函数调用和函数返回时的的函数调用关系和函数运行场景。
操作系统最基本的功能就是支持多线程编程,支持中断和异常处理,每个线程都有专属的栈,中断和异常处理也具有专属的栈。
3、程序的组成
一个程序本质上都是由.text段、.data段、.bss段三个组成的。
text段和data段都在可执行文件中(嵌入式系统一般时固化在镜像文件中),由系统从可执行文件加载。
bss段不在可执行文件中,由系统初始化
#include <stdio.h>
int arr[100000];
int main(void)
{
printf("hello,world!");
return 0;
}
#include <stdio.h>
int arr[10000]={0,1,2,3,4,5,6,7,8,9};
int main(void)
{
printf("hello,world!\n");
return 0;
}
程序2编译之后得到的可执行文件比程序1大很多。
所以,.bss是不占用可执行文件空间的,其内容由操作系统初始化;
.data需要占用,其内容由程序初始化。
.bss并不给该段的数据分配空间,只是记录数据所需空间的大小;
.data需要给数据分配空间,数据保存在目标文件中。
4、几种存储类型在内存空间中的分配
auto存储类型:对于局部变量,auto是默认的存储类型,不需要显示的指定。auto标识的变量存储在栈区中。
extern存储类型:extern用来声明在当前文件中引用当前项目中的其它文件中定义的全局变量。如果全局变量未被初始化,那么将被保存bss段中,更准确的说时记录在bss段,且在编译时,自动将其值赋值为0,如果已经被初始化,那么就被存在data段中。
register存储类型:register只是建议编译器将变量存储在寄存器中,声明为register的变量在由内存调入到CPU寄存器后,则常驻在CPU的寄存器中,因此访问register变量将在很大程度上提高效率,因为省去了变量由内存调入到寄存器过程中的好几个指令周期。所以,register 变量 存储在寄存器中或者栈中。
static存储类型:被声明为静态类型的变量,无论是全局的还是局部的,都存储在数据区中,其生命周期为整个程序,如果是静态局部变量,其作用域为一对{}内,如果是静态全局变量,其作用域为当前文件。静态变量如果没有被初始化,则自动初始化为0。静态变量只能够初始化一次。
字符串常量:字符串常量存储在数据区中,其生存期为整个程序运行时间,但作用域为当前文件。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int a = 0;//初始化的全局变量:保存在数据段
char *ptr1;//未初始化的全局变量:保存在BSS段
int main()
{
int b;//未初始化的局部变量:保存在栈上
char str[] = "abc";//"abc"为字符串常量保存在常量区;数组保存在栈上,
//并将常量区的"abc\0"复制到该数组中。这个数组可以随意修改而不会有任何隐患,
//而"123"这个字符串依然会保留在静态区中。
char *ptr2;//p2保存在栈上
char *ptr3 = "123456";//ptr3保存在栈上,"123456\0"作为字符串常量保存在常量区
//注意:如果令ptr3[1] = 9; 则程序崩溃,指针可以访问但不允许改变常量区的内容
//声明了一个指针ptr3并指向"123456\0"在常量区中的地址,事实上,ptr3应该声明为
//char const *,以免可以通过p3[i]='\n'这一类的语法去修改这个字符串的内容。
static int c = 0;//初始化的静态局部变量:保存在数据区的.data段
ptr1 = (char *)malloc(sizeof(char) * 10);//分配的10字节区域保存在堆上
ptr2 = (char *)malloc(sizeof(char) * 10);//分配的10字节区域保存在堆上
strcpy(ptr1,"123456");
//"123456\0"放在常量区,编译器可能会将它与p3所指向"123456"优化为一个地方
![img](https://img-blog.csdnimg.cn/img_convert/9d5cac4be4ed239c4007d6450a9a86ab.png)
![img](https://img-blog.csdnimg.cn/img_convert/f4c5e15dab6822677acc1424166c3bfd.png)
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新**
**需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618679757)**
全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新**
**需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618679757)**