存储类、作用域、生命周期、链接属性

以下内容源于朱有鹏嵌入式课程的学习,如有侵权,请告知删除。

补充:https://blog.csdn.net/oqqHuTu12345678/article/details/71214255

一、概念集合

1、存储类

(1)存储类就是存储类型,也就是描述C语言变量在何种地方存储

(2)内存有多种管理方法:栈、堆、数据段、bss段、.text段(代码段)……一个变量的存储类属性就是描述这个变量存储在何种内存段中。

 

  • 譬如局部变量分配在栈上,所以它的存储类就是栈;
  • 显式初始化为非0的全局变量分配在数据段,显式初始化为0和没有显示初始化(默认为0)的全局变量分配在bss段。

 

2、作用域

(1)作用域是描述这个变量起作用的代码范围

(2)基本来说,C语言变量的作用域规则是代码块作用域。

 

  • 即这个变量起作用的范围是当前的代码块。代码块就是一对大括号{}括起来的范围,所以一个变量的作用域是:这个变量定义所在的{}范围内从这个变量定义开始往后的部分。(这就解释了为什么变量定义总是在一个函数的最前面)

 

3、生命周期

(1)生命周期是描述这个变量什么时候诞生(运行时分配内存空间给这个变量)及什么时候死亡(运行时收回这个内存空间,此后再不能访问这个内存地址,或者访问这个内存地址已经和这个变量无关了)的。

(2)变量和内存的关系,就和人(变量)去图书馆借书(内存)一样。变量的生命周期就好象我人借书的这段周期一样。

(3)研究变量的生命周期可以我们理解程序运行的一些现象、理解C语言的一些规则。

 

4、链接属性

 

(1)程序从源代码到最终可执行程序,经历的过程:编译、链接。

 

  • 编译阶段就是把源代码搞成.o目标文件。
  • 目标文件里面有很多符号和代码段、数据段、bss段等分段。
  • 符号就是编程中的变量名、函数名等。
  • 运行时变量名、函数名能够和相应的内存对应起来,靠符号来做链接的。

(2).o的目标文件链接生成最终可执行程序的时候,其实就是把符号和相对应的段给链接起来。

 

(3)C语言中的符号有三种链接属性:外连接属性、内链接属性、无连接属性。

 

二、linux下C程序的内存映像

 

1、代码段、只读数据段

  • 对应着程序中的代码(函数),代码段在linux中又叫文本段(.text);
  • 只读数据段就是在程序运行期间只能读不能写的数据,const修饰的常量有可能是存在只读数据段的(但是不一定,const常量的实现方法在不同平台是不一样的)

2、数据段、bss段

 

  • 数据段存:1、显式初始化为非0的全局变量;2、显式初始化为非0的static局部变量
  • bss段存:1、显式初始化为0或者未显式初始化的全局变量;2、显式初始化为0或未显式初始化的static局部变量。

 

3、堆

 

  • C语言中什么样变量存在堆内存中?
  • C语言不会自动向堆中存放东西,堆的操作是程序员自己手工操作的。
  • 程序员根据需求自己判断要不要使用堆内存,用的时候自己申请,自己使用,完了自己释放。

 

4、文件映射区

 

  • 文件映射区就是进程打开了文件后,将这个文件的内容从硬盘读到进程的文件映射区,以后就直接在内存中操作这个文件,读写完了后在保存时再将内存中的文件写到硬盘中去。

 

5、栈

  • 局部变量分配在栈上;函数调用传参过程也会用到栈

7、内核映射区

 

  • 内核映射区就是将操作系统内核程序映射到这个区域了。
  • 对于linux中的每一个进程来说,它都以为整个系统中只有它自己和内核而已。
  • 它认为内存地址0xC0000000以下都是它自己的活动空间,0xC0000000以上是OS内核的活动空间。
  • 每一个进程都活在自己独立的进程空间中,0-3G的空间每一个进程是不同的(因为用了虚拟地址技术),但是内核是唯一的。

 

8、OS下和裸机下C程序加载执行的差异

(1)C语言程序运行时环境有一定要求

 

  • 意思是单独个人写的C语言程序没法直接在内存中运行,需要外部一定的协助,这段协助的代码叫加载运行代码(或者叫构建C运行时环境的代码,这一段代码在操作系统下是别人写好的,会自动添加到我们写的程序上,这段代码的主要作用是:给全局变量赋值、清bss段)。

 

(2)ARM裸机第十六部分,写shell时有一次定义了一个全局变量初始化为0但是实际不为0,后来在裸机的start.S中加了清bss段代码就变0了。

 

  • 这就说明在裸机程序中没人帮我们来做这一段加载运行时代码,要程序员自己做(start.S中的重定位和清bss段就是在做这个事);
  • 在操作系统中运行程序时程序员自己不用操心,会自动完成重定位和清bss,所以我们看到的现象:C语言中未初始化的全局变量默认为0。

 

(3)数据段的全局变量或静态局部变量都是有非0的初值的,这些初值在main函数运行之前就已经被初始化了,是重定位期间完成的初始化。

 

 

三、存储类相关的关键字

 

 

1、auto

 

  • auto关键字在C语言中只有一个作用,那就是修饰局部变量
  • 平时定义局部变量时就是定义的auto的,只是省略了auto关键字而已。可见,auto的局部变量其实就是默认定义的普通的局部变量。

 

2、static

(1)static的第一种用法是:用来修饰局部变量,形成静态局部变量。

 

  • 要搞清楚静态局部变量和非静态局部变量的区别。本质区别是存储类不同(存储类不同就衍生出很多不同)。
  • 非静态局部变量分配在栈上,而静态局部变量分配在数据段/bss段上。

 

(2)static的第二种用法是:用来修饰全局变量,形成静态全局变量。

 

  • 要搞清楚静态全局变量和非静态全局变量的区别。区别是在链接属性上不同。

 

3、register

(1)register修饰的变量。编译器会尽量将它分配在寄存器中(平时分配的一般的变量都是在内存中的)

 

  • 分配在寄存器中一样的用,但是读写效率会高很多。所以register修饰的变量用在那种变量被反复高频率的使用,通过改善这个变量的访问效率可以极大的提升程序运行效率时。所以register是一种极致提升程序运行效率的手段。

 

(2)uboot中用到了一个register类型的变量gd

 

  • 这个变量是用来存uboot的全局变量(gd就是global data)。因为这个全局变量在整个uboot中到处都被访问,所以定义成register的。

 

(3)平时写代码要被定义成register这种情况很少,一般慎用。

(4)register编译器只能承诺尽量将register修饰的变量放在寄存器中,但是不保证一定放在寄存器中。主要原因是因为寄存器数量有限,不一定有空用。

4、extern

(1)extern主要用来声明全局变量,声明的目的主要是在a.c中定义全局变量而在b.c中使用该变量。

 

  • C语言中程序的编译时以单个.c源文件为单位的,因此编译a.c时只考虑a.c中的内容(不会考了b.c的内容),这就导致a.c中使用了b.c中定义的变量时在编译时报错。解决方案是声明。
  • 应该在a.c中使用g_b之前先声明g_b,声明就是告诉a.c我在别的文件中定义了g_b,并且它的原型和声明的一样,将来在链接的时候链接器会在别的.o文件中找到这个同名变量。声明一个全局变量就要用到extern关键字

 

5、volatile

(1)C语言中volatile用来修饰一个变量,表示这个变量可以被编译器之外的东西改变。

 

  • 编译器之内的意思是变量的值的改变是代码的作用,编译器之外的改变就是这个改变不是代码造成的,或者不是当前代码造成的,编译器在编译当前代码时无法预知。
  • 譬如在中断处理程序isr中更改了变量的值,譬如多线程中在别的线程更改了这个变量的值,譬如硬件自动更改了这个变量的值(一般这个变量是一个寄存器的值)。
  • 中断isr中引用的变量,多线程中共用的变量,硬件会更改的变量,三者都是编译器在编译时无法预知的更改,此时应用使用volatile告诉编译器这个变量属于这种(可变的、易变的)情况。编译器在遇到volatile修饰的变量时就不会对改变量的访问进行优化,就不会出现错误。

 

(2)编译器的优化在一般情况下非常好,可以帮助提升程序效率。但是在特殊情况(volatile)下,变量会被编译器想象之外的力量所改变,此时如果编译器没有意识到而去优化则就会造成优化错误,优化错误就会带来执行时错误。而且这种错误很难被发现。

(3)volatile是程序员意识到需要volatile然后在定义变量时加上volatile,如果你遇到了应该加volatile的情况而没有加程序可能会被错误的优化。如果在不应该加volatile而加了的情况程序不会出错只是会降低效率。所以我们对于volatile的态度应该是:正确区分,该加的时候加不该加的时候不加,如果不能确定该不该加为了保险起见就加上。

6、restrict

(1)c99中才支持的,所以很多延续c89的编译器是不支持restrict关键字,gcc支持的。

(2)restrict也是和编译器行为特征有关的。

(3)restrict只用来修饰指针,不能修饰普通变量。

(4)http://blog.chinaunix.net/uid-22197900-id-359209.html

(5)memcpy和memmove的区别

7、typedef

 

  • typedef在C语言关键字归类上属于存储类关键字,但是实际上和存储类没关系。

 

 

四、作用域详解

 

1、局部变量的代码块作用域

  • 代码块基本可以理解为一对大括号{}括起来的部分。
  • 代码块不等于函数,因为if  while for都有{}。所以代码块<=函数。
  • 局部变量的作用域是代码块作用域,也就是说一个局部变量可以被访问和使用的范围仅限于定义这个局部变量的代码块中定义式之后的部分。

 

2、函数名和全局变量的文件作用域

 

 

  • 文件作用域的意思就是全局的访问权限,也就是说整个.c文件中都可以访问这些东西。这就是平时所说的局部和全局,全局就是文件作用域。
  • 详细准确的说:函数和全局变量的作用域是定义所在的整个.c文件之内定义式之后的部分。

 

3、注意

 

  • 在c89标准的编译器中(现在很多编译器还延续使用c89标准),所有的局部变量必须先定义在最前面,在变量定义之前不能有一句执行代码。
  • 在c99标准的编译器中(gcc兼容c99标准)可以允许在代码块内任意地方定义变量。但是允许定义的变量还是只能使用在定义了之后,定义之前还是不能用的。

 

4、同名变量的掩蔽规则

 

  • 问题:编程时,不可避免会出现同名变量。变量同名后不一定会出错。
  • 首先,如果两个同名变量作用域不同且没有交叠,这种情况下同名没有任何影响。
  • 其次,如果两个同名变量作用域有交叠,C语言规定在作用域交叠范围内,作用域小的一个变量会掩蔽掉作用域大的那个(县官不如现管)。

 

五、变量的生命周期

1、栈变量的生命周期

  • 局部变量(栈变量)存储在栈上,生命周期是临时的。临时的意思就是说:代码执行过程中按照需要去创建、使用、消亡的。
  • 譬如一个函数内定义的局部变量,在这个函数每一次被调用时都会创建一次,然后使用,最后在函数返回的时候消亡。
  • 思考:一个函数内的局部变量为什么在函数外不能使用?
  • 思考:局部变量为什么分配在栈上?或者说局部变量为什么是临时生命周期?

 

2、堆变量的生命周期

 

  • 首先要明白:堆内存空间是客观存在的,是由操作系统维护的。我们程序只是去申请然后使用然后释放。
  • 我们只关心我们程序使用堆内存的这一段时间,因此堆变量也有了自己的生命周期,就是:从malloc申请时诞生,然后使用,直到free时消亡。
  • 所以堆内存在malloc之前和free之后不能再去访问,因此堆内存在实践编程时都是被反复的malloc和free的。

 

3、数据段、bss段变量的生命周期

 

  • 全局变量的生命周期是永久的。永久的意思就是在程序被执行时诞生,在程序终止时消亡。
  • 全局变量所占用的内存是不能被程序自己释放的,所以程序如果申请了过多的全局变量会导致这个程序一直占用大量内存。

 

4、代码段、只读段的生命周期

 

  • 其实就是程序执行的代码,其实就是函数,它的生命周期是永久的。不过一般代码的生命周期我们并不关注。
  • 有时候放在代码段的不只是代码,还有const类型的常量,还有字符串常量。(const类型的常量、字符串常量有时候放在rodata段,有时候放在代码段,取决于平台)

 

六、链接属性

 

1、C语言程序的组织架构:多个C文件+多个h文件

  • (完整的一个C语言程序(譬如linux内核、uboot)由多个c文件和多个h文件组成的。
  • 程序的生成过程就是:编译+链接。
  • 编译是为了将函数/变量等变成.o二进制的机器码格式,链接是为了将各个独立分开的二进制的函数链接起来形成一个整体的二进制可执行程序。

2、编译以文件为单位、链接以工程为单位

  • 编译器工作时是将所有源文件依次读进来,单个为单位进行编译的。
  • 链接的时候实际上是把第一步编译生成个单个的.o文件整体的输入,然后处理链接成一个可执行程序。

3、三种链接属性:外连接、内链接、无链接

  • 外连接的意思就是外部链接属性,也就是说这家伙可以在整个程序范围内(言下之意就是可以跨文件)进行链接,譬如普通的函数和全局变量属于外连接。
  • 内链接的意思就是(c文件内部)内部链接属性,也就是说这家伙可以在当前c文件内部范围内进行链接(言下之意就是不能在当前c文件外面的其他c文件中进行访问、链接)。static修饰的函数/全局变量属于内链接。
  • 无连接的意思就是这个符号本身不参与链接,它跟链接没关系。所有的局部变量(auto的、static的)都是无连接的

4、函数和全局变量的同名冲突

(1)因为函数和全局变量是外部链接属性,就是说每一个函数和全局变量将来在整个程序中所有的c文件都能被访问,因此在一个程序中的所有c文件中不能出现同名的函数/同名的全局变量。

(2)最简单的解决方案就是起名字不要重复,但是很难做到。主要原因是一个很大的工程中函数和全局变量名字太多了,而且一个大工程不是一个人完成的,是很多人协作完成,所以很难保证不会重名。解决方案呢?

(3)现代高级语言中完美解决这个问题的方法是命名空间namespace(其实就是给一个变量带上各个级别的前缀)。但是C语言不是这么解决的。

 

  • C语言比较早碰到这个问题,当时还没发明namespace概念,当时C语言就发明了一种不是很完美但是凑活能用的解决方案,就是三种链接属性的方法。
  • C语言的链接属性解决重名问题思路是这样的:我们将明显不会在其他c文件中引用(只在当前c文件中引用)的函数/全局变量,使用static修饰使其成为内链接属性,这样在将来连接时即使2个c文件中有重名的函数/全局变量,只要其中一个或2个为内链接属性就没事。
  • 这种解决方案在一定程度上解决了问题。但是没有从根本上解决问题,留下了很多麻烦。所以这个就导致了C语言写很大型的项目难度很大。

 

5、static的第二种用法:修饰全局变量和函数

  • 普通的(非静态)的函数/全局变量,默认的链接属性是外部的;
  • static(静态)的函数/全局变量,链接属性是内部链接。

 

七、总结

1、普通(自动)局部变量分配在栈上,作用域为代码块作用域,生命周期是临时,连接属性为无连接。定义时如果未显式初始化则其值随机,变量地址由运行时在栈上分配得到,多次执行时地址不一定相同,函数不能返回该类变量的地址(指针)作为返回值。

2、静态局部变量分配在数据段/bss段(显式初始化为非0则在数据段,显式初始化为0或未显示初始化则在bss段),作用域为代码块作用域(人为规定的),生命周期为永久(天然的),链接属性为无连接(天然的)。定义时如果未显式初始化则其值为0(天然的),变量地址由运行时环境在加载程序时确定,整个程序运行过程中唯一不变;静态局部变量其实就是作用域为代码块作用域(同时链接属性为无连接)的全局变量。静态局部变量可以改为用全局变量实现(程序中尽量避免用全局变量,因为会破坏结构性)。

3、静态全局变量/静态函数和普通全局变量/普通函数的唯一差别是:static使全局变量/函数的链接属性由外部链接(整个程序所有文件范围)转为内部链接(当前c文件内)。这是为了解决全局变量/函数的重名问题(C语言没有命名空间namespace的概念,因此在程序中文件变多之后全局变量/函数的重名问题非常严重,将不必要被其他文件引用的全局变量/函数声明为static可以很大程度上改善重名问题,但是仍未彻底解决)。

4、写程序尽量避免使用全局变量,尤其是非static类型的全局变量。能确定不会被其他文件引用的全局变量一定要static修饰。

5、注意区分全局变量的定义和声明。一般规律如下:如果定义的同时有初始化则一定会被认为是定义;如果只是定义而没有初始化则有可能被编译器认为是定义,也可能被认为是声明,要具体分析;如果使用extern则肯定会被认为是声明(实际上使用extern也可以有定义,实际上加extern就是明确声明这个变量为外部链接属性)。

6、全局变量应该定义在c文件中并且在头文件中声明,而不要定义在头文件中(因为如果定义在头文件中,则该头文件被多个c文件包含时该全局变量会重复定义)。

7、在b.c中引用a.c中定义的全局变量/函数有2种方法:一是在a.h中声明该函数/全局变量,然后在b.c中#include <a.h>;二是在b.c中使用extern显式声明要引用的函数/全局变量。其中第一种方法比较正式。

8、存储类决定生命周期,作用域决定链接属性。

9、宏和inline函数的链接属性为无连接。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/461079.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java动态交叉表,SqlServer如何生成动态交叉表查询

为了说明问题&#xff0c;我们用SqlServer自带的事例数据库(Northwind)来进行验证&#xff0c;所有的例子请放到Northwind中运行&#xff0c;我可能会省略Use语句&#xff0c;所引用的表&#xff0c;都是Northwind中的&#xff0c;下面我就不再说明了这里指的交叉表&#xff0c…

Canvas Clock

这两天在看html5的canvas,实现了上面那个东西 需要注意的地方&#xff1a; 1.canvas的sava()和restore()理解和使用 2.canvas的translate scale rotate ..的使用&#xff0c;每个变化都应该清楚圆心和角度..看&#xff1a;http://blog.sina.com.cn/s/blog_8fab526c01015tqs.htm…

CentOS 6.3 下用ntfs-3g挂载Windows NTFS分区

2019独角兽企业重金招聘Python工程师标准>>> 默认情况下&#xff0c;CentOS 6.3不支持Widows NTFS硬盘分区读写&#xff0c;要想把NTFS格式的磁盘挂载到CentOS 6.3下面需要安装第三方的插件ntfs-3g&#xff0c;这里我们采用编译安装插件。 1、安装编译器&#xff0c…

宏定义与预处理、函数和函数库

以下内容源于朱有鹏嵌入式课程的学习&#xff0c;如有侵权&#xff0c;请告知删除。 一、C语言预处理理论 1、由源码到可执行程序的过程 源码.c->(编译)->elf可执行程序源码.c->(编译)->目标文件.o->(链接)->elf可执行程序源码.c->(编译)->汇编文件.S…

PictureBox

代码添加图片&#xff1a; pictureBox1.Image Image.FromFile("F:\360wallpaper_dt.jpg"); http://msdn.microsoft.com/query/dev10.query?appIdDev10IDEF1&lZH-CN&kk(SYSTEM.WINDOWS.FORMS.PICTUREBOX);k(TargetFrameworkMoniker-%22.NETFRAMEWORK%2cVERS…

C++的const修饰

2019独角兽企业重金招聘Python工程师标准>>> C的const修饰 ‍const的两个用途‍ &#xff08;1&#xff09;可以定义 const 常量 &#xff08;2&#xff09;const 可以修饰函数的参数、返回值. const的好处 &#xff08;1&#xff09;便于进行类型检查&#xff0c;…

链表(单链表、双链表、内核链表)

以下内容源于朱有鹏嵌入式课程的学习&#xff0c;如有侵权&#xff0c;请告知删除。 一、链表的引入 1、从数组的缺陷说起 数组有2个缺陷&#xff0c;一个是数组中所有元素的类型必须一致&#xff1b;第二个是数组的元素个数必须事先制定并且一旦指定之后不能更改。数组的第一…

心率变异性 matlab,心率变异性好的功率谱分析方面的问题

本帖最后由 天路 于 2018-2-25 21:16 编辑本人正在学习心率变异性方面的内容&#xff0c;但是按照文献上的方法做出来的结果并不是很理想&#xff0c;文献上说的是心率变异性的频率的范围是0.4以内&#xff0c;但是我做的功率谱上显示频率分布在整个频域内&#xff0c;试了很多…

C#获取Windows下光标位置(转)

使用C#获取光标相对于显示器屏幕的位置&#xff1a; 方式一&#xff1a; 1 [csharp] view plaincopyprint?2 using System; 3 using System.Drawing; 4 using System.Runtime.InteropServices; 5 6 namespace ColorPicker 7 { 8 /// <summary> 9 /// win…

[Android Studio] Android Studio如何提示函数用法

Eclipse有一个很好的功能&#xff0c;就是当你代码调用某个android API时&#xff0c;鼠标移到对应的函数或者方法上&#xff0c;就会自动有一个悬 浮窗提示该函数的说明&#xff08;所包含的参数含义&#xff0c;该方法功能&#xff09;。迁移到Android Studio后&#xff0c;这…

uboot源码——链接脚本u-boot.lds分析

以下内容源于朱有鹏嵌入式的学习与整理&#xff0c;如有侵权&#xff0c;请告知删除。 uboot的链接脚本u-boot.lds&#xff0c;位于uboot根目录下的/board/samsung/x210目录。 脚本内容与分析如下&#xff1a; /** (C) Copyright 2002* Gary Jennejohn, DENX Software Engi…

php 调用 com,PHP调用COM函数

用PHP调用windows中的COM相关函数&#xff1a;函数列表&#xff1a;com_load — 创建一个COM组件的引用。com_invoke — 调用一个COM组件的方法。com_propget — 取一个COM组件的属性的值。com_get — 同上&#xff0c;取一个COM组件的属性的值。com_propput — 赋一个值给一个…

struts2--java.lang.IllegalAccessException: Class ognl.OgnlRuntime can not access a member of

这个问题是我碰到的一个比较纠结的问题&#xff0c;如果第一次碰到肯定能让你也很纠结&#xff0c;哈哈 [c-sharp] view plaincopyprint? 01.2010-10-19 18:27:22 com.opensymphony.xwork2.util.logging.jdk.JdkLogger warn 02.警告: Error setting expression nnew.nTitle …

情怀真的可以吃~致文青

说实在的&#xff0c;这首歌名如其实的平凡。最标准的Trip-Hop节奏&#xff0c;最普通的四个和弦&#xff0c;最没有惊喜的合成器音色&#xff0c;歌词也是那山那山的波澜不惊。就是这么一首平平无奇的歌&#xff0c;却在首发的7个小时内&#xff0c;狂刷一百万次试听点击。 …

决策树php,决策树模型组合之随机森林与GBDT

前言&#xff1a;决策树这种算法有着很多良好的特性&#xff0c;比如说训练时间复杂度较低&#xff0c;预测的过程比较快速&#xff0c;模型容易展示(容易将得到的决策树做成图片展示出来)等。但是同时&#xff0c;单决策树又有一些不好的地方&#xff0c;比如说容易over-fitti…

关于uboot的简介——uboot的目录结构

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 不同版本的uboot&#xff0c;或者同一版本不同人员移植的uboot&#xff0c;目录结构和文件内容都会有所不同&#xff0c;也就是说&#xff0c;可以根据需要去添加、删除或者更改目录结构。在以三星的…

为何不精通C? 03 深入剖析声明

对于复杂的C函数声明&#xff0c;或者被typedef别名后的声明&#xff0c;很多人往往一头雾水。本文主要解析下C语言中声明过程所遵循的原则。 声明 引用《C专家编程》的第三章内容&#xff0c;说明下声明的优先级规则&#xff1a; 声明从它的名字开始读&#xff0c;然后按照优先…

Photoshop绘制植物大战僵尸中的食人花

本人意见&#xff1a;我打算使用本文中的食人花形象作为我的一次讲课中的主要参考。我想说明的是&#xff0c;通过FLASH和PS都能够轻松地绘制出如本文所描述的食人花卡通效果。独立游戏开发者如果安排好时间&#xff0c;完全可以通过1-2个月掌握FLASH和PS绘制&#xff08;想精通…

ios手机 php无法上传文件,【已解决】uni.uploadFile 苹果ios图片上传不成功

安卓正常上传&#xff0c;苹果里我到相册里选了一张20k的图片&#xff0c;服务器都得不到数据&#xff0c;服务器端是PHP&#xff0c;$_FILES居然是空的&#xff0c;下面是简单的代码openPic(){var that this;uni.chooseImage({count: 1,sourceType: [album, camera],sizeType…

uboot源码——uboot启动内核过程总结

总结的思维导图&#xff0c;其下载地址&#xff1a;Uboot启动.mmap_免费高速下载|百度网盘-分享无限制 第一阶段&#xff1a;汇编阶段&#xff0c;即start.S文件的工作。 第二阶段&#xff1a;C代码阶段&#xff0c;即start_armboot函数的工作。 值得一提的是&#xff0c;star…