嵌入式面试题

2023-05-16

首先给大家分享一个在线练习面试题的网站:牛客网。

该网站包含使用实例、应用技巧、基本知识点总结和需要注意事项,具有参考价值,需要的朋友可以参考一下

嵌入式面试题-点击进行练习

嵌入式面试题

  • 第一部分:基本概念
    • 1.关键字static的作用
    • 2.引用与指针的区别:
    • 3..h头文件中的#ifndef/#define/#endif作用:
    • 4.#include <>与#include “”区别:
    • 5.描述实时系统的基本特性:
    • 6.全局变量与局部变量是否存在区别?
    • 7.堆栈溢出一般是由于什么原因?
    • 8.冒泡排序算法的时间复杂度
    • 9.什么函数不能声明为虚函数?
    • 10.队列与栈的区别:
    • 11.不能做switch()的参数类型
    • 12.局部变量是否能和全局变量重名?
    • 13.如果引用一个已经定义过的全局变量?
    • 14.全局变量能不能定义在可被多个.c文件包含的头文件中?
    • 15.for(;1;)有什么问题?什么意思?
    • 16.do…while()与while…do有什么区别?
    • 17.static全局变量、局部变量、函数与普通全局变量、局部变量、函数有什么区别?
    • 18.程序的内存分配
    • 19.堆和栈的区别
    • 20.什么是预编译,什么时候需要预编译?
    • 21.关键字const含义
    • 22.关键字volatile含义?应用例子:
    • 23.三种基本数据模型
    • 24.结构体与联合体有什么区别
    • 25.#define与const区别:
    • 26.数组与指针区别:
    • 27.分别写出bool、int、float、指针类型的变量a与零比较的语句:
    • 28.如何判断一段程序是由c编译还是由c++编译程序编译的?
    • 29.讨论含参数的宏与函数优缺点:
    • 30.使用两个栈来实现一个队列的功能
    • 31.位操作
    • 32.访问固定的内存位置
    • 33.中断
    • 34.typedef
    • 35.写一个“标准”的宏
    • 更多面试资料分享

第一部分:基本概念

1.关键字static的作用

(1)在函数体内:一个被声明为静态的变量,在这一函数被调用过程中,维持其值不变。(该变量值初始化一次)

(2)在模块内,函数体外:一个被声明为静态的变量,可以被模块内所用函数访问,但不能被模块外其他函数访问。

(3)在模块内,一个被声明为静态的函数,该函数只能被这一模块内其他函数调用,其他模块无法调用。

2.引用与指针的区别:

(1)引用必须初始化,指针不用

(2)引用初始化后不能修改,指针可以改变所指对象

(3)不存在指向空的引用,指针存在空值

指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。

引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。

3…h头文件中的#ifndef/#define/#endif作用:

防止头文件被重复引用

4.#include <>与#include “”区别:

<>是从系统指定的路径下寻找;””是先从当前路径下寻找

5.描述实时系统的基本特性:

在特定时间内完成特定的任务,实时性与可靠性。

6.全局变量与局部变量是否存在区别?

全局变量存在静态数据区,局部变量存在栈中

7.堆栈溢出一般是由于什么原因?

(1)没有回收垃圾资源

(2)层次太深的递归调用

8.冒泡排序算法的时间复杂度

O(n^2)

9.什么函数不能声明为虚函数?

构造函数

10.队列与栈的区别:

队列:先进先出;栈:先进后出

11.不能做switch()的参数类型

实型

12.局部变量是否能和全局变量重名?

可以。局部变量会屏蔽全局变量。若要使用全局变量,使用::。

在函数内引用该重名变量时,会使用同名的局部变量,而不会使用全局变量(就近原则)。

对一些编译器而言,同一函数内可以定义多个同名的局部变量,例如:在两个循环体内都定义一个同名的局部变量,而那个局部变量的作用域就在该循环内。

13.如果引用一个已经定义过的全局变量?

可以包含其头文件,也可使用关键字extern。

引用头文件:通过引用头文件的方式来引用某个头文件中声明的变量,假如将该变量写错了,在编译阶段会报错。

extern:通过extern的方式引用,若将变量写错,编译阶段编译器不会报错,在链接阶段会进行报错提示。

14.全局变量能不能定义在可被多个.c文件包含的头文件中?

可以。在不同的C文件中以static的形式来声明同名全局变量。

可以在不同的C文件中声明同名的全局变量,前提是只能在一个C文件中对变量赋初值,此时链接不会报错。

15.for(;1;)有什么问题?什么意思?

与while(1)相同,无限循环

16.do…while()与while…do有什么区别?

前者循环一遍后再判断;后者先判断后循环

17.static全局变量、局部变量、函数与普通全局变量、局部变量、函数有什么区别?

(1)static全局变量与非static全局变量区别:

存储方式上相同,都是静态存储。

作用域:非static全局变量的作用域在各个文件中都是有效的;static的全局变量作用域只限于当前源文件中,只初始化一次。

(2)static函数与普通函数作用域不同。Static函数只能在当前源文件中使用,而非Static函数可以在其他源文件中使用。

(3)static局部变量只初始化一次,下次调用使用上次的数值。

18.程序的内存分配

C/C++编译的程序占用的内存分为以下几部分。

(1) 栈区,编译器自动分配释放,存放函数的参数值,局部变量的值等。操作方式类似于数据结构中的栈。

(2) 堆区,由程序员分配释放。若程序员没有进行资源回收,程序结束时,可能会由OS回收。与数据结构中的堆是两回事。

(3) 全局区(静态区),全局变量与静态变量是存储在一起的。初始化的全局变量与初始化的静态变量在一块区域,未初始化的全局变量与未初始化的静态变量存储在一起。程序结束后由OS释放

(4) 常量区,存储常量,字符串。程序结束后由OS回收。

(5) 程序代码区,存放函数体的二进制代码。

示例:

int a = 0; //全局初始化区域
char *p1; //全局未初始化区域

int main(int argc, char const *argv[]) {
 int b; //栈
 char s = "sss"; //栈
 char *p2; //栈
 char *p3 = "123456"; //p3在栈上,“123456\0”在常量区
 static int c = 0; //全局初始化区域
 
 p1 = (char *)malloc(10); //分配得到的区域在堆上
 p2 = (char *)malloc(20);
 strcpy(p1, "123456"); //“123456\0”在常量区
 return 0;
}

19.堆和栈的区别

(1)申请方式:

堆:由程序员申请,在c语言中使用malloc函数申请。(嵌入式单片机应用中不建议使用此函数)。

例如:p2 = (char *)malloc(10),p2本身是在栈上。

C++中,new运算符

栈:由系统分配。

(2)申请后系统响应:

栈:若当前栈的剩余空间大于申请空间,系统将会给程序提供内存;否则,将提示异常,栈溢出。

堆:操作系统有个记录空闲内存地址的链表,当系统收到程序的申请时,将会遍历该链表,寻找第一个内存空间大于所申请空间的堆节点,然后将该节点从链表中删除,并将该内存空间分配给程序。找到的堆节点的大小不一定正好等于申请的大小,此时系统会将多余的部分重新放入空闲链表中。对于大多数系统,这块内存空间的首地址会记录本次分配的大小,这样,代码中的delete语句才能正确释放该块内存空间。

(3)申请大小的限制:

栈:在windows下,栈是向低地址扩展的数据结构,是一块连续的内存区域(栈顶地址与容量是系统提前规定好的)。

堆:堆是向高地址扩展的数据结构,是不连续的内存区域。堆的大小限制于系统中有效的虚拟内存。

(4)申请效率:

栈:由系统自动分配,速度快,但程序员无法操作。

堆:由new、malloc分配,速度慢,容易产生内存碎片,但使用方便。

Windows下最好使用virtual alloc分配内存,这块内存既不在堆,也不在栈,是直接在进程的地址空间中保留一块内存,速度快,灵活,使用不方便。

(5)堆和栈中的存储内容

栈:在函数调用时,是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数C语言编译器中,参数是由右往左入栈的,然后是函数中的局部变量。静态变量不入栈,在全局初始化区域。

当函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续执行。

堆:一般在堆的头部用一个字节存储堆的大小。堆中的具体内容由程序员分配。

(6)存取效率比较:

Char s1[] = “ssssss”;

Char *s2 = “bbbbbb”;

aaaaaa是在运行时赋值的,bbbbbb是在编译时确定的。

但在以后的存取中,栈上的数组比指针指向的字符串(堆)块。

void main() {
char a = 1;
char c[] = "1234567890";
char *p = "1234567890";

a = c[1];
a = p[1];

return;
}

对应的汇编代码

10:a=c[1];
004010678A4DF1movcl,byteptr[ebp-0Fh]
0040106A884DFCmovbyteptr[ebp-4],cl
11:a=p[1];
0040106D8B55ECmovedx,dwordptr[ebp-14h]
004010708A4201moval,byteptr[edx+1]
004010738845FCmovbyteptr[ebp-4],al
第一种:在读取时,直接将字符串中的元素读到寄存器c1中

第二种:先将指针读取到edx中,再根据edx读取字符。

20.什么是预编译,什么时候需要预编译?

预编译又称为预处理,是做代码文本的替换工作,处理#开头的指令,比如拷贝#include包含的头文件代码;#define宏定义的替换。在程序开始编译之前进行。

C语言编译系统在对程序编译之前,先进行预处理。预处理主要提供以下功能:

(1)宏定义(2)头文件包含(3)条件编译

21.关键字const含义

const 只读

应用:

const int a; //常整型数

int const a; //常整型数

const int *a; //a是一个指向常整型数的指针(指针可以修改,整型数不可修改)

int * const a; //a是一个指向整型数的常指针(指针不可以修改,整型数可以修改)

const int * const a; //a是一个指向常整形数的常指针(都不可修改)

使用const关键字的理由:

(1) 为读代码的人提供非常有用的信息,实际上应用一个参数为常量是为了告诉用户这个参数的应用目的。

(2) 通过给优化器一些附加信息,使用关键字const也许能够产生更紧凑的代码

(3) 合理使用const可以使编译器很自然的保护那些不希望被修改的参数,防止其被无意的代码修改。

22.关键字volatile含义?应用例子:

含义:

一个被定义为volatile的变量是说这个变量可能会被意想不到的改变,这样编译器就不会去假设这个变量的值了。准确的说,优化器在用到这个变量时,必须每次都小心点重新读取这个变量的值,而不是直接使用寄存器中的备份值。

应用:
(1)并行设备的硬件寄存器

(2)一个中断服务子程序中会访问到的非自动变量。

(3)多线程应用中被几个任务共享的变量

其他问题:

  1. 一个参数既可以是const还可以是volatile吗?为什么?

  2. 一个指针可以是volatile吗

  3. 下面函数有什么错误

int square(volatile int *ptr) {

Return *ptr * *ptr;

}

(1) 可以,一个例子为只读的状态寄存器。它是volatile是应为他可能被意想不到的改变。它是const是应为程序不因该去修改它。

(2) 是的,虽然不常见。一个例子为中断服务子程序修改一个指向一个buffer的指针时。

(3) 这段代码的目的是为了返回指针ptr的平方,但是由于ptr是一个指向volatile类型的参数,因此编译器将产生类似于下面的代码:

int square(volatile int *ptr) {
  int a, b;
  A = *ptr;
  B = *ptr;
  Return a * b;
}

由于*ptr的值可能被意想不到的改变,因此,a与b的值可能不同,结果这段代码返回的结果与预期可能并不相同。

正确代码:

int square(volatile int *ptr) {
  int a;
  A = *ptr;
  Return a * a;
}

23.三种基本数据模型

按照数据结构类型的不同,将该数据模型划分为层次模型、网状模型、关系模型

24.结构体与联合体有什么区别

共用体,允许在相同的内存地址存储不同的数据类型;可以定义一个带有多成员的共用体,但是任何时候只能有一个成员带有值。共用体提供了一种使用相同内存地址的方式

共用体,占用的内存应该足够存储共用体中最大的成员。

结构体,占用内存是内部所有变量所占空间之和。结构体,每个成员变量都有自己的内存地址。

25.#define与const区别:

1.const有数据类型,宏定义没有数据类型;编译器可以对前者进行安全检查,对于后者不能进行安全检查,只能进行字符替换。

2.有些调试工具可以对const进行调试,而宏定义无法调试。

3.const定义的常量有作用域,而#define不重视作用域,默认定义处到文件结尾。

26.数组与指针区别:

数组要么在静态数据区被创建,要么在栈上被创建。

指针可以随时指向任意类型的内存块。

(1)修改内容上的差别:

char a[] = “hello”;

A[0] = ‘x’;

Char *p = “world”;//p指向的是常量字符串

P[0] = ‘x’;//编译器无法发现该错误,运行时会报错

(2)使用sizeof()运算符计算容量:

数组可以使用sizeof计算出容量,而sizeof§计算得到的是一个指针变量的字节数,一般为4个字节,而不是p所指向的内存容量。

注意:当数组作为函数形参进行传递时,该数组自动退化为同类型指针:

void TestBufferSize1(char a[]) {
    printf("buffer size = %d \r\n", sizeof(a));
}

void TestBufferSize2(char a[6]) {
    printf("buffer size = %d \r\n", sizeof(a));
}

int main(){
    char b[6] = "12345";
    printf("b size = %d \r\n", sizeof(b));
    TestBufferSize1(b);
    TestBufferSize2(b);
    system("pause");
}

27.分别写出bool、int、float、指针类型的变量a与零比较的语句:

(1)bool:

if(!a) or if(a)

(2)int

if(a == 0)

(4)float:

const EXPRESSION EXP = 0.000001

If(a < EXP && a >-EXP)

(5)指针:

if(a != NULL) or if(a == NULL)

28.如何判断一段程序是由c编译还是由c++编译程序编译的?

#ifdef __cplusplus
    cout << "c++";
#else
    printf("c");
#endif

29.讨论含参数的宏与函数优缺点:

带参宏 函数
处理时间 编译时 程序运行时
参数类型 没有参数类型问题 定义实参,形参类型
处理过程 不分配内存 分配内存
程序长度 变长 不变
运行速度 不占用运行时间 调用和返回占用运行时间

30.使用两个栈来实现一个队列的功能

设两个栈A,B,并将其初始化为空

入队:

将新元素push入栈A;

出队:

(1) 判断栈B是否为空

(2) 若不为空,则将栈A中的所有元素依次pop出,并push到栈B

(3) 将栈B的栈顶元素pop出

这样的实现,入队与出队的平摊复杂度都为O(1)

31.位操作

给定一个整型变量a,写两段代码,第一个设置a的bit 3,第二个清除a的bit 3。在以上操作中,保持其它位不变。

(1) 通过宏定义,以及bit masks操作。这种方法可移植性高

#define BIT3 (0x01 << 3)

static int a;

void SetBit3(void) {
    a |= BIT3;
}

void ClearBit3(void) {
    a &= ~BIT3;
}

(2) 使用bit fields。Bit fields是被扔到C语言死角的方式。这种方法保证了你的代码在不同编译器之间是不可移植的,同时也保证代码是不可重用的。

32.访问固定的内存位置

嵌入式编程中,经常会去访问某个特定内存位置的数据。在某个工程中,需要设置一个绝对地址为0x56a3的整型变量的值为0x3344。编译器是一个纯粹的ANSI编译器。

(1) 方法一:

int *ptr = NULL;
ptr = (int *)0x56a3;
*ptr = 0x3344;

(2) 方法二:

*(int * const)(0x56a3) = 0x3344;

推荐使用第一种。

33.中断

中断是嵌入式系统中重要的组成部分,这导致了很多编译开发商提供了一种扩展—让标准C支持中断。

具体代表的事实是,产生了一个新的关键字__interrupt。

下面这段代码使用了__interrupt关键字去定义了一个中断服务子程序(ISR),请评价这段代码。

__interrupt double compute_area(double radius) {
 double area = PI * radius * radius;
 printf("\nArea = %f", area);
 return area;
}

(1) ISR不能返回一个值

(2) ISR不能传递参数

(3) 在许多编译器中,浮点数一般是不可重入的。并且,ISR应该是短而有效的,在ISR中做浮点数运算是不明智的。

(4) Printf()经常有重入与性能上的问题

34.typedef

Typedef 在C语言中频繁用以声明一个已经存在的数据类型的同义字。也可以用预处理器做类似的事情。

例:

#define dPS struct s *
Typedef struct s *tPS;

以上两种情况都是要定义dPS和tPS作为一个指向结构s的指针。哪种方法更好?

答:typedef更好,原因请看下面示例。

dPS s1,s2;
tPS s3,s4;

第一个展开为struct s *s1,s2;此时,s1指向的是结构的指针,而s2是一个实际的结构。

35.写一个“标准”的宏

(1)交换两个参数的宏定义

#define SWAP(a, b)\
        (a) = (a) + (b);\
        (b) = (a) - (b);\
        (a) = (a) - (b);\

(2)输入两个参数,输出较小的参数

#define MIN(a, b) (((a) < (b)) ? (a) : (b))

(3)1年中有多少秒?(忽略闰年)

#define SECONDS_OF_YEAR (60 * 60 * 24 * 365)UL

(4)已知一个数组table,使用宏定义求出数组元素的个数

#define TABLE_SIZE (sizeof(table) / siezof(table[0]))

更多面试资料分享

  • https://gitee.com/lighter-z/embedded-base

  • 嵌入式面试题-点击进行练习

  • 链接: https://pan.baidu.com/s/1k4mN–E1xl6rZSLSqFP6Aw 提取码:d8h3

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

嵌入式面试题 的相关文章

随机推荐

  • 运行mmsegmentation碰到报错:size shape must match input shape. Input is 2D, size is 3

    运行mmsegmentation碰到报错 xff1a size shape must match input shape Input is 2D size is 3 这个问题比较坑 有时候我们的标签size是 512 xff0c 512 x
  • (docker笔记):镜像原理之联合文件系统、分层理解、commit 镜像

    目录 Docker 镜像讲解 什么是镜像 xff1f Docker 镜像加载原理 分层理解 commit 镜像 Docker 镜像讲解 什么是镜像 xff1f 镜像是一种轻量级 可执行的独立软件包 xff0c 用来打包软件运行环境和基于运行
  • FCOS报错ImportError: libcudart.so

    在使用detectron2 43 AdelaiDet运行FCOS代码时 xff0c 碰到报错 xff1a from adet import C ImportError libcudart so 10 0 cannot open shared
  • 在Ubuntu18.04(Melodic)中安装ROS Gazebo经验总结

    首先实现Win10系统 与 Ubuntu18 04 之间实现粘贴复制 span class token function sudo span span class token function apt span span class tok
  • 解决ResourceNotFound: gazebo_ros

    roslaunch simulation landing px4 launch 错误如下 ResourceNotFound gazebo ros ROS path 0 61 opt ros kinetic share ros ROS pat
  • Ubuntu18.04下java环境安装flightplot分析软件

    Java安装参考我的这篇博文 Linux 系统小白 Ubuntu 18 04下安装 Java 过程简单总结 安装flightplot过程如下 1 xff1a sudo apt install git 2 xff1a git clone re
  • estimatePoseSingleMarkers()解读

    ex 网页长截图 1 F12 2 ctrl 43 shift 43 p 3 Capture full size screenshot 参考网址 estimatePoseSingleMarkers void cv aruco estimate
  • 插值函数总结(下篇之二维插值)

    命令2 interp2 功能 xff1a 二维数据内插值 xff08 表格查找 xff09 格式1 xff1a z1 61 interp2 x y z x1 y1 返回矩阵z1 xff0c 其元素包含对应于参量x1与y1 xff08 可以是
  • 模型预测控制算法(MPC算法)底层逻辑

    目录 MPC算法的基本原理 详细解析 预测模型中需要注意的点 滚动优化需要注意的点 构造目标函数约束部分 约束部分 举例说明 复盘总结 MPC算法的基本原理 MPC 的基本原理可以分为三个步骤 xff1a 预测模型 滚动优化 反馈校正 xf
  • 计算机视觉(三)--- 图像到图像的映射(全景拼接)

    目录 1 基本介绍 2 RANSAC 3 单应性矩阵估计 4 全景图像 1 基本介绍 引言 众所周知 xff0c 在我们拍摄风光摄影时 xff0c 广角镜头是使用频率最高的镜头 xff0c 特别是拍摄那些波澜壮阔的大场景风光 而且镜头可谓是
  • 机器学习课后练习题(期末复习题目附答案)

    此为第一章绪论部分 一 单选题 1 移动运营商对客户的流失进行预测 可以使用下面哪种机器学习方法比较合适 A 一元线性回归分析 B 关联方法 C 聚类算法 D 多层前馈网络 正确答案 A 2 下面哪种说法有关机器学习的认识是错误的 A 高质
  • STM32野火教程学习笔记

    欢迎使用STM32 虽然经历了疫情期间的价格起飞 xff0c 但是STM32系列的单片机仍然是各个控制领域内主流的微控制器 它是控制人的必修课之一 STM32的编程方法 我们在学习51单片机的时候 xff0c 通常是通过编写程序直接对其输入
  • Docker的使用

    目录 Docker概念 Docker安装 配置docker加速器 Docker命令 docker进程命令 docker镜像命令 容器命令 Docker容器的数据卷 数据卷概念 数据卷配置 数据卷容器 docker部署mysql 1 搜索my
  • launch启动文件的使用方法

    launch文件 xff1a 脚本 xff0c 可以把很多节点的启动写进去 Launch文件语法 1 lt launch gt launch文件中的根元素采用 lt launch gt 标签定义 2 lt node gt pkg xff1a
  • 基于单片机的电子万年历的设计

    文末下载完整资料 基于51单片机的电子万年历的设计 摘 要 电子万年历是单片机系统的一个应用 xff0c 由硬件和软件相配合使用 硬件由主控器 时钟电路 温度检测电路 显示电路 键盘接口5个模块组成 主控模块用AT89C52 时钟电路用时钟
  • 基于单片机的数字钟设计

    文末下载完整资料 摘 要 基于单片机的定时和控制装置在许多行业有着广泛的应用 xff0c 而数字钟是其中最基本的 xff0c 也是最具有代表性的一个例子 在基于单片机系统的数字钟电路中 xff0c 除了基本的单片机系统和外围电路外 xff0
  • 电子设计大赛-电源电路

    文末下载完整资料 集成直流稳压电源的设计 直流稳压电源是电子设备的能源电路 xff0c 关系到整个电路设计的稳定性和可靠性 xff0c 是电路设计中非常关键的一个环节 本节重点介绍三端固定式 xff08 正 负压 xff09 集成稳压器 三
  • 总线的分类和区别

    总线分类 xff1a 点击查看原文 全套资料免费下载 xff1a 关注v x 公 众 号 xff1a 嵌入式基地 后 台 回 复 xff1a 电赛 即可获资料 回复 编程 即可获取 包括有 xff1a C C 43 43 C JAVA Py
  • 电子设计大赛-室内可见光定位装置

    室内可见光定位装置 1 1 设计任务 设计并制作可见光室内定位装置 xff0c 其构成示意图如图 1 所示 参赛者自行搭建不小于 80cm 80cm 80cm 的立方空间 xff08 包含顶部 底部和 3 个侧面 xff09 顶部平面放置
  • 嵌入式面试题

    首先给大家分享一个在线练习面试题的网站 xff1a 牛客网 该网站包含使用实例 应用技巧 基本知识点总结和需要注意事项 xff0c 具有参考价值 xff0c 需要的朋友可以参考一下 嵌入式面试题 点击进行练习 嵌入式面试题 第一部分 xff