拿下嵌入式软件工程师面试题(day1)

前言

(1)如果你在读大学,不管你本科毕业是读研还是就业,你都可以早点准备嵌入式面试题,本系列教程的面试题均基于C语言。

(2)像嵌入式学得好,且学历不错的本科生和研究生,都有机会进入华为、小米、大疆、智元等公司,薪资待遇也是不错的。

(3)早点接触面试题,心里有底,大家一起学起来吧。

(4)希望各位大佬多多指点经验,大家一起交流,共同进步!本人邮箱:3201935299@qq.com

第一题(考查对volatile关键字的认识——华为)

#include<setjmp.h>
static jmp_buf  buf;main()    
{volatile  int b;b =3;if(setjmp(buf)!=0)  {printf("%d ", b);  exit(0);}b=5;longjmp(buf , 1);
}

请问,这段程序的输出是

(a) 3
(b) 5
© 0
(d) 以上均不是

第一题答案(b)5

详细解析

(1)volatile是C语言中的一个关键字,用于声明一个变量为"易变"(volatile)。当一个变量被声明为volatile时,编译器将对该变量的访问和操作做出特殊处理,以确保对该变量的读写操作不会被优化、重排序或省略,从而提供对变量的准确和可预测的访问。
(2)这是因为这个变量可能在一个寄存器,直接与外部设备相连,你写入之后,该寄存器也有可能被外部设备的写操作所改变;或者,该变量被一个中断程序,或被另一个进程改变了。
(3)volatile 不会被编译器优化影响,在longjump 后,它的值是后面假定的变量值,b最后的值是5,所以5被打印出来.

(4)setjmp : 设置非局部跳转 /* setjmp.h*/

Lonjjmp: 执行一个非局部跳转 /* setjmp.h*/

反思

(1)请先允许见识狭窄的我先说一句,我用了两年C语言都没见过<setjmp.h>这个头文件,以至于我开始都以为这题考的不是C语言哈哈,直到我把题目代码在VS里编译后,才相信,还是学的东西太少了,一下子暴露了自己的知识上限(doge),其次题目代码少包含了一个头文件#include <stdio.h>。这个程序看似很复杂,实际超级简单。

在这里插入图片描述

我提出问题,头文件<setjmp.h>有什么作用?函数setjmp()、longjmp()是什么作用?该程序的逻辑功能是什么?

(2)头文件<setjmp.h>有什么作用?

头文件<setjmp.h>是C标准库中的一个头文件,它提供了用于非局部跳转的函数setjmp()和longjmp()的声明和定义。

setjmp()和longjmp()函数允许在程序的不同位置进行跳转,而不是按照正常的顺序执行代码。这种非局部跳转的能力对于处理异常、错误处理、状态回滚等情况非常有用。

具体来说,<setjmp.h>头文件中提供的函数有以下作用:

setjmp()函数:用于设置一个跳转点,并将当前程序状态保存到jmp_buf类型的变量中。它在设置跳转点时返回0,但当通过longjmp()函数跳转回来时,setjmp()函数会返回非零值,用于判断是否发生了跳转。

longjmp()函数:用于进行非局部跳转,返回到之前通过setjmp()函数设置的跳转点。它的第一个参数是之前保存的jmp_buf变量,第二个参数是用于标识跳转原因的值。

通过结合使用setjmp()和longjmp()函数,可以实现一种跳转回之前的程序状态的机制,从而实现异常处理、错误处理、状态回滚等操作。

需要注意的是,由于非局部跳转可能会导致代码流程的混乱和难以维护,应该谨慎使用setjmp()和longjmp()函数,并确保在使用时遵循相关的规范和最佳实践。

(3)函数setjmp()、longjmp()是什么作用?

函数setjmp()longjmp()是C标准库中提供的用于非局部跳转的函数。

  1. setjmp()函数:setjmp()函数用于设置一个跳转点,并将当前程序状态保存到一个jmp_buf类型的变量中。它的原型如下:

    int setjmp(jmp_buf env);
    `````setjmp()`函数在设置跳转点时返回0,并将程序状态保存在`env`变量中。这样,通过调用`longjmp()`函数可以跳回到`setjmp()`函数所在的位置,并恢复保存的程序状态。
    
  2. longjmp()函数:longjmp()函数用于进行非局部跳转,返回到之前通过setjmp()函数设置的跳转点。它的原型如下:

    void longjmp(jmp_buf env, int value);
    `````longjmp()`函数接受一个`jmp_buf`类型的变量`env`作为参数,以及一个用于标识跳转原因的整数值`value`。调用`longjmp()`函数会使程序跳转回`setjmp()`所在的位置,并且`setjmp()`函数的返回值被设置为`value`。
    

这种非局部跳转的机制可以用于异常处理、错误处理以及特定的控制流程需求。例如,当发生某个异常情况时,可以使用setjmp()函数设置一个跳转点,然后在需要的地方调用longjmp()函数跳转回来,从而实现异常处理。这种机制在一些C语言框架和库中被广泛使用,例如错误处理和资源回收的实现。

需要注意的是,非局部跳转是一种强大但也容易导致代码复杂性和难以维护性的特性,因此在使用时应慎重考虑,并确保遵循相关的规范和最佳实践。

(4)程序逻辑分析

这段代码展示了使用C标准库中的setjmp()和longjmp()函数来实现非局部跳转的示例。

首先,jmp_buf是一个用于存储跳转位置信息的数据类型。在代码中,我们声明了一个名为buf的jmp_buf类型变量。

接下来,main()函数中声明了一个volatile修饰符的整型变量b,并将其初始化为3。

然后,通过使用setjmp(buf)函数,在此处设置了一个跳转点。setjmp()函数会将当前程序状态保存到buf中,并返回0作为返回值。这是第一次调用setjmp()函数,因此返回值为0。

之后,代码中的条件判断语句if(setjmp(buf)!=0)检测到setjmp()函数的返回值不为0,表示发生了跳转。在这种情况下,程序会执行跳转后的代码块。

在跳转后的代码块中,通过调用printf()函数输出变量b的值,并调用exit(0)函数来终止程序运行。

然而,在跳转之前,我们将变量b的值修改为5。

最后,通过调用longjmp(buf, 1)函数,程序将跳转回之前设置的跳转点,并且setjmp()函数的返回值被设置为1。这会导致条件判断语句为真,从而执行跳转后的代码块。

综上所述,这段代码的输出结果将是"5"。

Tips

(1)需要注意的是,volatile关键字只会影响对变量的访问和修改行为,而不会影响变量本身的类型或存储方式。volatile并不提供线程安全性或互斥访问的保证,因此在多线程环境中使用volatile变量时需要额外的同步机制。

(2)以下是一个示例,展示了volatile变量的使用:

#include <stdio.h>int main() {volatile int counter = 0;while (counter < 10) {printf("Counter: %d\n", counter);counter++;}return 0;
}

在这个程序中,我们声明了一个 volatile 整数变量 counter。volatile 关键字的作用是告诉编译器,该变量的值可能会被意外地改变,因此在编译器优化过程中不要对该变量进行优化。

在这个示例中,counter 变量在每次循环迭代时增加 1,然后将其值打印出来。由于 counter 是 volatile 类型的,编译器会确保每次循环都会读取变量的最新值,而不是依赖于缓存或寄存器中的旧值。这样可以确保输出的结果是连续递增的数字,而不是出现不连续或重复的数字。

如果我们将 counter 声明为非 volatile 类型,编译器可能会进行优化,例如将 counter 的值保存在寄存器中,以避免每次迭代都从内存中读取。这样可能导致打印出的结果不符合预期,例如可能会输出重复的数字或者不按顺序递增。

因此,使用 volatile 关键字可以确保程序正确地处理那些可能被意外改变的变量,如硬件寄存器、多线程环境下的共享变量等。

Volatile在嵌入式中的应用:

可以去看看别人做项目的程序中什么时候用volatile,加以理解;光看白话文,而不看代码,很难理解透彻。

当我们使用 volatile 关键字修饰变量时,我们告诉编译器该变量的值可能在程序的其他地方被意外地修改,因此编译器不应该对该变量进行某些优化,以确保程序的行为符合我们的预期。

volatile 关键字的作用主要有以下几个方面:

(1)防止编译器优化:编译器在进行代码优化时,为了提高程序的性能和效率,可能会对变量进行优化,例如将变量存储在寄存器中,而不是每次都从内存中读取。然而,这种优化可能导致问题,特别是当变量的值可能会在程序的其他地方被修改时。通过使用 volatile 关键字,我们告诉编译器不要对这些变量进行优化,每次都从内存中读取最新的值。

(2)处理硬件寄存器:在嵌入式系统或与硬件交互的程序中,我们经常需要使用 volatile 关键字来处理硬件寄存器。硬件寄存器是与外部设备直接通信的接口,其值可以在任何时候被修改。通过使用 volatile 关键字修饰硬件寄存器,我们确保编译器不会对寄存器的读取和写入进行优化,并且始终与硬件保持同步。

(3)处理多线程共享变量:在多线程编程中,多个线程可能同时访问和修改共享变量。这种情况下,使用 volatile 关键字可以确保每个线程都能正确地读取和写入共享变量的最新值,而不会依赖于线程本地的缓存。volatile 关键字提供了一种简单的同步机制,用于确保可见性和一致性。

(4)需要注意的是,volatile 关键字并不能解决所有的并发问题,它只能保证可见性和一致性,但不能提供原子操作或线程安全。对于更复杂的多线程场景,需要使用其他同步机制,如互斥锁(mutex)或原子操作来保证线程安全性。

综上所述,使用 volatile 关键字可以确保变量在特定的场景下的可见性和一致性,避免编译器的优化干扰。它在处理硬件寄存器、多线程共享变量或其他需要确保变量值正确性的情况下非常有用。

第二题(考查类型转换)

main()
{struct node {int a;int b;int c;     };struct node  s= { 3, 5,6 };struct node *pt = &s;printf("%d" ,  *(int*)pt);}

请问这段程序的输出是:

(a) 3
(b) 5
© 6
(d) 7

第二题答案(a) 3

详细解析

(1)这段代码定义了一个结构体node,其中包含三个整型成员变量a、b和c。然后创建了一个名为s的node类型的结构体变量,并初始化其成员变量为3、5和6。

(2)接下来,声明了一个指向node类型结构体的指针pt,并将其指向结构体变量s的地址。

(3)最后,通过使用类型转换

(int*)

将指针pt转换为指向整型的指针,然后使用间接访问运算符

*

对其进行解引用,即

*(int*)pt

这样可以将指针pt解释为指向整型变量的指针,并取得该整型变量的值

(4)最终,通过调用printf()函数,将解引用后的整型值打印出来。

(5)根据代码中的初始化,输出结果将是3,因为pt指向s结构体的起始地址,而在s结构体中,第一个成员变量a的值为3。

第三题(考查递归调用)

int  foo ( int x , int  n) 
{int val;val =1;if (n>0) {if (n%2 == 1)  val = val *x;val = val * foo(x*x , n/2);}return val;
}

这段代码对x和n完成什么样的功能(操作)?

(a) x^n (x的n次幂)
(b) x*n(x与n的乘积)
© n^x(n的x次幂)
(d) 以上均不是

第三题答案(a)

详细解析

这段代码定义了一个名为foo的递归函数,用于计算一个整数x的n次幂。

函数内部有一个局部变量val,并将其初始化为1。

接下来,通过嵌套的条件语句进行递归计算。首先,判断n是否大于0。如果是,进入第一个内部条件语句。

在第一个内部条件语句中,判断n是否为奇数(即n % 2 == 1)。如果是奇数,将val乘以x,即val = val * x。

然后,调用foo()函数本身,传入x的平方和n除以2的结果。这样就实现了递归调用,将问题规模减半。

递归调用在函数内部进行,通过每次将n减半的方式,最终达到递归的结束条件(即n等于0,其实n/2小于1就结束了,因为是形参是int类型)。当n等于0时,递归函数返回1。

最后,在函数的最外层,返回变量val的值。

通过这种递归的方式,函数foo()可以计算x的n次幂,并将结果作为返回值返回。

需要注意的是,对于较大的n值,由于递归的深度增加,可能导致栈溢出或性能下降。在实际使用中,需要注意递归调用的层数和性能影响。

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

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

相关文章

mysql8 Found option without preceding group错误

这个错误说起来是真的坑&#xff0c;今晚帮同学在window操作系统上安装mysql8当自定义my.ini文件的时候 就出现一下错误&#xff0c;死活启动不起来 一直报错。当删掉这个my.ini文件的时候却能启动&#xff0c;刚开始以为是my.ini里的配置选项不对&#xff0c;一个一个筛查后依…

抖音小店爆款制造指南:打造抖音爆款商品的八大技巧

抖音小店作为一种电商模式&#xff0c;通过短视频形式展示商品&#xff0c;吸引用户购买。在抖音平台上&#xff0c;打造爆款商品是每个抖音小店主的梦想。以下是四川不若与众整理的一些抖音小店如何打造爆款商品的技巧。 1. 产品选择&#xff1a;选择适合抖音平台的产品非常重…

鲁棒优化入门(6)—Matlab+Yalmip两阶段鲁棒优化通用编程指南(上)

0.引言 上一篇博客介绍了使用Yalmip工具箱求解单阶段鲁棒优化的方法。这篇文章将和大家一起继续研究如何使用Yalmip工具箱求解两阶段鲁棒优化(默认看到这篇博客时已经有一定的基础了&#xff0c;如果没有可以看看我专栏里的其他文章)。关于两阶段鲁棒优化与列与约束生成算法的原…

Window安装虚拟机+给虚拟机安装Linux

一、虚拟机下载 这里使用Virtualbox虚拟机。可以直接从官网下载&#xff1a;Downloads – Oracle VM VirtualBox 点击进行下载&#xff0c;选择window版本的。直接双击&#xff0c;一直下一步 进行安装 PS&#xff1a;安装需要开启CPU虚拟化&#xff0c;一般电脑都已经开启了…

c语言实训心得3篇集合

c语言实训心得体会一&#xff1a; 在这个星期里&#xff0c;我们专业的学生在专业老师的带领下进行了c语言程序实践学习。在这之前&#xff0c;我们已经对c语言这门课程学习了一个学期&#xff0c;对其有了一定的了解&#xff0c;但是也仅仅是停留在了解的范围&#xff0c;对里…

Qt6_贪吃蛇Greedy Snake

贪吃蛇Greedy Snake 1分析 首先这是一个贪吃蛇界面&#xff0c;由一个长方形边框和一只贪吃蛇组成 默认开局时&#xff0c;贪吃蛇身体只有3个小方块&#xff0c;使用画笔画出 1.1如何移动 对于蛇的移动&#xff0c;有2种方法 在一定时间范围内(定时器)&#xff0c;未对游戏…

知识大杂烩(uniapp)

首先声明&#xff1a;不敢保证都管用&#xff0c;这是我自己实践得来的。 box-shadow: 这段 CSS 样式代码用于创建一个阴影效果&#xff0c;它是通过 box-shadow 属性来实现的。让我解释一下这段代码的含义&#xff1a; - box-shadow: 这是 CSS 的属性&#xff0c;用于添加阴影…

vue3集成jsoneditor

一、背景 之前在做录制回放平台的时候&#xff0c;需要前端展示子调用信息&#xff0c;子调用是一个请求列表数组结构&#xff0c;jsoneditor对数组的默认展示结构是[0].[1].[2]..的方式&#xff0c;为了达到如下的效果&#xff0c;必须用到 onNodeName的钩子函数&#xff0c;…

微信小程序navigateTo进入页面后返回原来的页面需要携带数据回来

需求 如图&#xff1a;点击评论后会通过wx.navigateTo进入到评论页面&#xff0c;评论完返回count给原页面&#xff0c;重新赋值实现数量动态变化&#xff0c;不然要刷新这个页面才会更新最新的评论数量。 实现方式&#xff1a; 在评论页面通过wx.setStorageSync(‘data’…

智慧工厂的未来:视频+数字孪生与工业4.0的融合

视频数字孪生技术在智慧工厂项目中具有广泛的应用&#xff0c;为生产制造提供了前所未有的机会和优势。下面将探讨数字孪生技术在智慧工厂项目中的多个应用场景。 数字孪生技术的首要应用之一是生产流程优化。通过将现实世界的工厂映射到数字孪生模型中&#xff0c;制造…

Scrum认证高级Scrum Master (A-CSM) 认证培训课程

课程简介 高级ScrumMaster (Advanced Certified ScrumMaster, A-CSM) 认证课程是国际Scrum联盟推出的进阶级Scrum认证课程&#xff0c;是Scrum Master通往专业级敏捷教练必经的学习路径。 在ScrumMaster&#xff08;CSM&#xff09;认证课程中&#xff0c;您学习到了Scrum的价…

应用出海,Google 分享如何让数字营销素材再上层楼

数字营销广告要想取得理想的效果&#xff0c;广告素材是最关键的决定因素之一。 事实上米贸搜谷歌推广发现&#xff0c;在广告给品牌带来的销售额增量中&#xff0c;有 47% 都归功于广告素材。在当今自动化时代&#xff0c;广告素材的作用尤其重要&#xff1a;固然机器可以完成…

微信视频号不能插入公众号链接,需要绑定公众号?

耐心往下看&#xff0c;我们给你解决 微信视频号不能插入公众号链接&#xff0c;必须要绑定公众号才能添加 视频号不能挂公众号文章链接&#xff0c;不仅手机端不可以&#xff0c;在电脑端也不可以。 这件事说明&#xff1a;视频号规则越来越严格&#xff0c;就算你绑定成功…

Web安全——Web安全漏洞与利用上篇(仅供学习)

SQL注入 一、SQL 注入漏洞1、与 mysql 注入的相关知识2、SQL 注入原理3、判断是否存在注入回显是指页面有数据信息返回id 1 and 114、三种 sql 注释符5、注入流程6、SQL 注入分类7、接受请求类型区分8、注入数据类型的区分9、SQL 注入常规利用思路&#xff1a;10、手工注入常规…

通过Docker Compose安装MQTT

一、文件和目录说明 1、MQTT安装时的文件和目录 EMQX 安装完成后会创建一些目录用来存放运行文件和配置文件&#xff0c;存储数据以及记录日志。 不同安装方式得到的文件和目录位置有所不同&#xff0c;具体如下&#xff1a; 注意&#xff1a; 压缩包解压安装时&#xff0c;目…

大模型扫盲之小白入门手记

本篇内容来自小米集团数据科学部负责人刘汉武老师的数据特训营笔记。不涉及深入的知识&#xff0c;仅在扫盲。 首先一个问题&#xff1a;大模型和大语言模型的区别是什么&#xff1f; 有人说大模型像是连接数据的星辰&#xff0c;能给我们提供前所未有的见解和洞察。现有的大模…

扩散模型 DDPM 核心代码梳理

参考内容&#xff1a; 大白话AI | 图像生成模型DDPM | 扩散模型 | 生成模型 | 概率扩散去噪生成模型 AIGC 基础&#xff0c;从VAE到DDPM 原理、代码详解 全网最简单的扩散模型DDPM教程 The Annotated Diffusion Model LaTeX公式编辑器 备注&#xff1a; 具体公式的推导请查看…

【聚类】K-Means聚类

cluster&#xff1a;簇 原理&#xff1a; 这边暂时没有时间具体介绍kmeans聚类的原理。简单来说&#xff0c;就是首先初始化k个簇心&#xff1b;然后计算所有点到簇心的欧式距离&#xff0c;对一个点来说&#xff0c;距离最短就属于那个簇&#xff1b;然后更新不同簇的簇心&a…

OpenCV(二十八):连通域分割

目录 1.介绍连通域分割 2.像素领域介绍 3.两遍法分割连通域 4.连通域分割函数 1.介绍连通域分割 连通域分割是一种图像处理技术&#xff0c;用于将图像中的相邻像素组成的区域划分为不同的连通域。这些像素具有相似的特性&#xff0c;如相近的灰度值或颜色。连通域分割可以…

C高级第2天

写一个1.sh脚本&#xff0c;将以下内容放到脚本中&#xff1a; 在家目录下创建目录文件&#xff0c;dir 在dir下创建dir1和dir2 把当前目录下的所有文件拷贝到dir1中&#xff0c; 把当前目录下的所有脚本文件拷贝到dir2中 把dir2打包并压缩为dir2.tar.xz 再把dir2.tar.xz…