zoukankan      html  css  js  c++  java
  • 1-嵌入式面试题库

    嵌入式工程师:主要从事嵌入式软件开发工作,涉及应用层以及底层软件开发和设计的工作。以应用为中心,计算机技术为基础,软硬件可裁剪,适用于应用系统对功能、可靠性、成本、体积、功耗有严格要求的专用计算机系统。嵌入式产品一般由嵌入式微处理器、外围硬件设备、嵌入式操作系统以及用户程序等四个部分构成,用于对其他设备控制、监护、管理。

    面试题目(自我介绍/项目/代码量/):

    (1)程序的局部变量存在于哪里,全局变量存在于哪里,动态申请数据存在于哪里?

    答:程序的局部变量存在于栈区;全局变量存在于静态区;动态申请数据存在于堆区。

    什么是代码区、常量区、静态区(全局区)、堆区、栈区?

    代码区:存放程序的代码,即CPU执行的机器指令,并且是只读的;
    常量区:存放常量(程序在运行的期间不能够被改变的量,例如: 10,字符串常量”abcde”, 数组的名字等);

    ①常量区内容在运行过程中不可改变


    静态区(全局区、变量区):静态变量和全局变量的存储区域是一起的,一旦静态区的内存被分配, 静态区的内存直到程序全部结束之后才会被释放;


    堆区:由程序员调用malloc()函数来主动申请的,需使用free()函数来释放内存,若申请了堆区内存,之后忘记释放内存,很容易造成内存泄漏;

    ① 申请动态区域的时候,使用完记得释放它,如果不释放 ,这块内存就不可用了,会导致内存泄露;

    ② 释放的时候只能释放一次,不要重复释放,因为释放后的内存可能会去做别的事情,重复释放会出现问题,释放完后让这个指针最好指向空地址,避免下次用这个指针的时候出现地址错误。

    栈区:存放函数内的局部变量,形参和函数返回值。栈区之中的数据的作用范围过了之后,系统就会回收自动管理栈区的内存(分配内存 , 回收内存),不需要开发人员来手动管理。栈区就像是一家客栈,里面有很多房间,客人来了之后自动分配房间,房间里的客人可以变动,是一种动态的数据变动。

    ① 局部变量不要定义的太大,不然占用非常大的栈区空间,会导致栈溢出;

    ② 栈用于函数嵌套调用、中断切换时保存和恢复现场数据。调用函数不要有深层次的调用,调用函数的过程中栈区会不停的存储函数的一些相关的变量、地址之类的,如果有深层次函数递归的需要,尽量采用别的方式去替代它;

    ③ 栈:后进先出,只能在一端(称为栈顶(top))对数据项进行插入和删除。位于其中间的元素,必须在其栈上部(后进栈者)诸元素逐个移出后才能取出。所以和我们函数调用的过程是类似的,最先调用的函数总是最后返回,而最后调用的函数则是最最先返回,也就后调用先返回。栈的出栈方式决定函数的返回过程,栈的增长空间支持函数嵌套的复杂程度。

    堆中定义了 两个最重要的操作是PUSH和POP。 PUSH(入栈)操作:堆栈指针(SP)加1,然后在堆栈的顶部加入一 个元素。POP(出栈)操作相反,出栈则先将SP所指示的内部ram单元中内容送入直接地址寻址的单元中(目的位置),然后再将堆栈指针(SP)减1。这两种操作实现了数据项的插入和删除。

    ④ 每次我们开机的时候,系统都会初始化好栈指针(SP),初始方法也很简单,在boot_load代码里我们可以看到:ldr sp, =4096   这样的语句,实际就是让SP指针指向这样的地址,但是注意,这个地址是内存中的地址,而不是cpu片内地址,内存资源相对cpu资源来说充裕多了,所以SP可以有很大的增长空间,这也是C语言可以写复杂程序的前提。

     

    内存分区的示意图。一般内存主要分为:代码区、常量区、静态区(全局区)、堆区、栈区这几个区域。
    这里写图片描述

    宏定义不占内存空间,在预处理阶段被展开替换掉,可执行文件中不存在宏定义,所以它不占用内存空间。

    全局、静态局部变量存在在静态区(变量区、全局区)

    局部变量存在于:栈区

    申请动态存储区:堆区

    常量存在于:常量区

    调用的函数存在:代码区

     

    变量放在堆区(heap)和栈区(stack)区别:

    从申请方式、申请大小、申请效率三方面进行比较:

    申请方式:Stack的空间由操作系统自动分配/释放,Heap上的空间手动分配/释放;

    申请大小:Stack空间有限(一般2M),Heap是很大的自由存储区;

    申请效率:栈是由系统自动分配的,速度较快,但程序员是无法控制的; 堆一般速度比较慢,而且容易产生内存碎片,不过用起来最方便。

     

     

    (2)引用与指针有什么区别?

    1、引用必须被初始化,指针不必。

    2、引用初始化以后不能被改变,指针可以改变所指的对象。

    3、不存在指向空值的引用,但是存在指向空值的指针。

    (3)一个 32 位的机器,该机器的指针是多少位?

    答:指针是多少位只要看地址总线的位数就行了。80386 以后的机子都是32的数据总线。所以指针的位数就是 4 个字节了。

     

    (4)请解释什么是“有名管道”?

    有名管道 (named pipe) :有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。

    高级管道(popen):将另一个程序当做一个新的进程在当前程序进程中启动,则它算是当前程序的子进程,这种方式我们成为高级管道方式。

     

    (5)线程是否具有相同的堆栈?

    答:真正的程序执行都是线程来完成的,程序启动的时候操作系统就帮你创建了一个主线程。每个线程有自己的堆栈。

     

    (6)请解释什么是“套接字”?

    套接字(socket) :套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信。

     

    (7)嵌入式系统中经常要用到无限循环,如何用 C 编写死循环?

    答:while(1){}或者for(;;)

    (8)do……while和while有什么区别?

    答:前一个循环一遍再判断,后一个判断以后再循环。

     

    (9)static 全局变量与普通的全局变量有什么区别?static 函数与普通函数有什么区别?

    答:静态用于全局变量和函数,作用是限定他们的 作用域

    静态全局变量作用域是 只在本文件可见,从定义之处开始到本文件结束;

    静态局部变量作用域是  定义它的函数内部,其分配的内存知道程序运行结束才释放;

    静态函数只被当前文件调用。

     

    (10)关于死锁

    死锁的处理方式有哪些?

    答:死锁的处理方式主要从预防死锁、避免死锁、检测与解除死锁这四个方面来进行处理。

    请解释什么是“预防死锁”?

    预防死锁:

    1. 资源一次性分配:(破坏请求和保持条件)
    2. 可剥夺资源:即当某进程新的资源未满足时,释放已占有的资源(破坏不可剥夺条件)
    3. 资源有序分配法:系统给每类资源赋予一个编号,每一个进程按编号递增的顺序请求资源,释放则相反(破坏环路等待条件)

    什么是避免死锁?

    避免死锁:预防死锁的几种策略,会严重地损害系统性能。因此在避免死锁时,要施加较弱的限制,从而获得 较满意的系统性能。由于在避免死锁的策略中,允许进程动态地申请资源。因而,系统在进行资源分配之前预先计算资源分配的安全性。若此次分配不会导致系统进入不安全状态,则将资源分配给进程;否则,进程等待。其中最具有代表性的避免死锁算法是银行家算法。

    产生死锁的原因是什么?

    答:多个并发进程因争夺系统资源而产生相互等待的现象。即:一组进程中的每个进程都在等待某个事件发生,而只有这组进程中的其他进程才能触发该事件,这就称这组进程发生了死锁。

    产生死锁的本质原因为:系统资源有限、进程推进顺序不合理。

    死锁的 4 个必要条件是什么?

    1. 互斥:某种资源一次只允许一个进程访问,即该资源一旦分配给某个进程,其他进程就不能再访问,直到该进程访问结束。
    2. 占有且等待:一个进程本身占有资源(一种或多种),同时还有资源未得到满足,正在等待其他进程释放该资源。
    3. 不可抢占:别人已经占有了某项资源,你不能因为自己也需要该资源,就去把别人的资源抢过来。
    4. 循环等待:存在一个进程链,使得每个进程都占有下一个进程所需的至少一种资源。

    当以上四个条件均满足,必然会造成死锁,发生死锁的进程无法进行下去,它们所持有的资源也无法释放。这样会导致 CPU 的吞吐量下降。

    所以死锁情况是会浪费系统资源和影响计算机的使用性能的。那么,解决死锁问题就是相当有必要的了。

     

    (11)进程之间通信的途径有哪些?

    答:进程间通信主要通过管道、消息、信号等途径进行。

    (12)请解释什么是“共享内存”?

    答: 共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。

     

    (13)什么是预编译,何时需要预编译?

    预编译又称为预处理,是做些代码文本的替换工作,处理#开头的指令,比如拷贝#include包含的文件代码,#define宏定义的替换,条件编译等 就是为编译做的预备工作的阶段。

    1.总是使用不经常改动的大型代码体。

    2.程序由多个模块组成,所有模块都使用一组标准的包含文件和相同的编译选项。在这种情况下,可以将所有包含文件预编译为一个预编译头

    3.预编译指令指示了在程序正式编译前就由编译器进行的操作,可以放在程序中的任何位置

    编译性语言比如 C 或 C++ 写的程序需要将源代码通过预处理-编译-汇编-链接后,生成计算机可执行的机器码语言(二进制代码,即0和1)。

    • 预处理:展开#include头文件,宏替换、去掉注释、条件编译#if... ...
    • 编译:检查语法,生成汇编语言(.s文件)
    • 汇编:将汇编代码转换为机器码(.o文件)
    • 链接:将各个模块的机器码文件、依赖库连起来生成计算机可执行的文件

     

    (14)进程和线程有什么区别?

     

     (15)重写strcpy函数?

     

    (16)左值和右值

    左值:对应内存中有确定存储地址的对象的表达式的值。

    右值:所有不是左值的表达式的值。

    左值和右值的区分标准在于能否获取地址

    左值可写,右值可读。通常,左值可以作为右值,但是右值不一定是左值。

     

     

    什么是内核空间?什么是用户空间

    内核空间和用户空间通信方式

    为什么需要uboot?不用行不行?

    用uboot的目的是引导内核启动。

    我理解的,理论是可以的。把uboot中所做的一些工作写进内核里,板子也能启动。但是很少有人这么做,毕竟内核很庞大,大面积修改难度比较大。

     

    volatile关键字

     

     嵌入式上层c++/c和嵌入式底层c的部分

     

    Arm有几个寄存器?什么是CPSR,SPSR?什么时候用到?

    37个寄存器。CPSR是当前程序状态寄存器,存储的是当前程序的状态,比如上下文的一些寄存器内容,程序运行的话就要用到CPSR。SPSR为备份的程序状态寄存器,主要是中断发生时用来存储CPSR的值的。

     

    字符设备有哪些?和块设备有什么区别?如何写一个字符设备驱动?

      字符设备有键盘,鼠标等。字符设备和块设备的区别主要是访问方式不同,访问字符设备是以字符流的方式访问的,访问块设备是以块为单位,并且可以随机访问。

      以一个LED驱动为例,先定义一个file_operations结构体,接着编写init函数,在init函数中完成对管脚的映射,register_chrdev字符设备的注册,class_create类的注册,class_device_create在类下面注册一个设备。exit函数中完成字符设备的卸载,类的卸载,内存空间的释放。在open函数中完成硬件管脚的初始化,在write函数中完成点灯操作。

     

    uboot启动过程?

     

     

    反问:

    (1)如果我有幸能进入贵公司,主要负责那部分?

    (2)面试结果大概多久回复?

     

  • 相关阅读:
    Boost智能指针使用总结
    C++细节理解
    Mysql导入导出
    Mysql Join语法以及性能优化
    数据库设计三大范式
    Mysql子查询
    js面向对象的实现(example 一)
    js对象常用2中构造方法
    RequireJS 加载 easyui
    Cordova 打包 Android release app 过程详解
  • 原文地址:https://www.cnblogs.com/darren-pty/p/14331444.html
Copyright © 2011-2022 走看看