3道经典嵌⼊式C⾯试题
题⼀,堆和栈的区别是?
题⼆,Volatile与Register的区别是?
题三,ARM⾥的⼤端格式和⼩端格式分别是什么意思?
题⼀答案:
(1)存储内容不同
栈:在函数调⽤时,栈中存放的是函数中(最底下是函数调⽤后的下⼀条指令)的各个参数(局部变量)。
堆:⼀般是在堆的头部⽤⼀个字节存放堆的⼤⼩。堆中的具体内容由程序员分配。
(2)管理⽅式上不同
栈:由系统⾃动分配并释放空间。 例如,声明在函数中⼀个局部变量 int b; 系统⾃动在栈中为b开辟空间,当对应的⽣存周期结束后栈空间被⾃动释放。
堆:需要程序员指定⼤⼩⼿动申请和⼿动释放,在C语⾔中使⽤malloc函数申请,使⽤free函数释放。
(3)空间⼤⼩不同
栈:获取空间较⼩。在Windows下⼀般⼤⼩是1M或2M,当剩余栈空间不⾜时,分配失败overflow。
堆:获得空间根据系统的有效虚拟内存有关,⽐较灵活、⼤。
(4)能否产⽣碎⽚不同
栈:不会产⽣碎⽚,空间连续。
堆:采⽤的是链表的存储⽅式,会产⽣碎⽚。
(5)⽣长⽅向不同
栈: 向低地址扩展的数据结构,是⼀块连续的内存区域。
堆: 向⾼地址扩展的数据结构,是不连续的内存区域。这是由于系统是⽤链表空闲内存地址来存储的,⾃然不连续,⽽链表的遍历⽅向是由低地址向⾼地址。
(6)分配⽅式不同
栈:有2种分配⽅式:静态分配和动态分配,静态由编译器完成,例如局部变量;动态由malloc函数实现,由编译器进⾏释放。
堆: 都是动态分配的,没有静态分配的堆。
(7)分配效率不同
栈:由系统⾃动分配,速度较快。但程序员⽆法控制。
堆:由new分配的内存,⼀般速度⽐较慢,⽽且容易产⽣内存碎⽚,不过⽤起来最⽅便。
题⼆答案:
a.volatile
volatile是易变的,不稳定的意思,volatile是关键字,是⼀种类型修饰符,⽤它修饰的变量表⽰可以被某些编译器未知的因素更改,⽐如操作系统、硬件或者其他线程等,遇到这个关键字声明的变量,编译器对访问该变量的代码不在进⾏优化,从⽽可以提供对特殊地址的稳定访问。那么什么是编译器优化呢?
为了提⾼运⾏效率,攻城师们费尽⼼机地把代码优化,优化程序运⾏时存取速度。⼀般,分为硬件优化和软件优化。硬件优化,流⽔线⼯作,详细可以参考《计算机组成原理》。软件优化,⼀部分是程序猿们做的代码优化(前提你得有优化的思路和能⼒),还有⼀部分就是我们的编译器优化了。
现代的编译器经过那么多年的发展,已经⽐较成熟,它会把多余的变量忽略掉,让代码的运⾏效率更⾼。默认情况下,编译器都会对代码进⾏优化,会把⼀些变量在寄存器⾥存取,⽽不是在内存⾥存取,如此⼀来,CPU在⾃⼰家⾥拿东西当然⽐从内存那⾥拿东西要快得多。举个⼩栗⼦:
int i = 5;
int a = i;
……
int b = i;
编译器发现两次从i读数据的代码之间,并没有对i进⾏过操作,它会⾃动把上次读的数据放在b中,⽽不是重新从i⾥⾯读取。
⽽volatile关键字告诉编译器该变量是随时可能发⽣变化的,每次使⽤它的时候必须从内存中取出它的
值,因⽽编译器⽣成的汇编代码会从原内存地址中读取数据使⽤,⽽不是从寄存器或者缓存中读取,从⽽保证了对特殊地址的稳定访问。
简⾔之,状态要经常变化的,为了防⽌我们编译优化⽽导致的存取的数据不同步的问题,这时我们就需要⽤到volatile。那具体到什么场景下需要⽤到volatile关键字呢?
嵌入式系统是什么意思1、并⾏设备的硬件寄存器(如:状态寄存器);
2、⼀个中断服务⼦程序中会访问到的⾮⾃动变量();
3、多线程应⽤中被⼏个任务共享的变量;
上⾯提到了⾮⾃动变量,这⾥进⼀步对⼏种变量做⼀番解释:
⾃动变量:是在函数内部定义和使⽤的变量,它是局部变量。
⾮⾃动变量:有两种,⼀种是全局变量,⼀种是静态变量。
全局变量:在函数外⾯定义的变量,只能定义⼀次,不能有重复的定义,不然就会发⽣错误,⽽其他的⽂件要想使⽤这个变量,需要extern 来声明这个变量(也可省略,因为默认就是extern),这个声明叫做引⽤声明。
若不想被其他⽂件访问,则⽤static关键字声明为静态变量。静态变量与⾃动变量的本质区别是,静态变量并不像⾃动变量那样使⽤堆栈机制来使⽤内存。
⽽是为静态变量分配固定的内存,在程序运⾏的整个过程中,它都会被保持,⽽不会被销毁。这就是说静态变量的持续性是程序运⾏的整个周期。这有利于我们共享⼀些数据。
如果静态变量在函数内部定义,则它的作⽤域就是在这个函数内部,仅在这个函数内部使⽤它才有效,但是它不同于⾃动变量,⾃动变量离开函数后就会被销毁,⽽静态变量不会被销毁。他在函数的整个运⾏周期内都会存在。
b. register
这个关键字请求编译器尽可能的将变量存在CPU内部寄存器中,⽽不是通过内存寻址访问,以提⾼效率。注意是尽可能,不是绝对。你想想,⼀个CPU 的寄存器也就那么⼏个或⼏⼗个,你要是定义了很多很多register 变量,它累死也可能不能全部把这些变量放⼊寄存器吧。
题三答案:
当前的存储器,多以byte为访问的最⼩单元,当⼀个逻辑上的地址必须分割为物理上的若⼲单元时就存在了先放谁后放谁的问题, 于是端(endian)的问题应运⽽⽣了, 对于不同的存储⽅法, 就有⼤端(big-en
dian)和⼩端(little- endian)两个描述。
字节排序按分为⼤端和⼩端,概念如下
⼤端(big endian): 低地址存放⾼有效字节
⼩端(little endian): 低字节存放低有效字节
现在主流的CPU, intel系列的是采⽤的little endian的格式存放数据,⽽motorola系列的CPU采⽤的是big endian,ARM则同时⽀持 big 和little。
举个例⼦
int a = 0x12345678;
a是四字节的int类型变量,需要占四个字节空间,假设变量a的⾸地址是0x2000,那么数据存储在地址中的格式如下:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论