当前位置: 首页 > news >正文

(七)嵌入式面试题收集:8道

题目 1

请完成下面的宏定义,作用是获得 a 和 b 两个参数中的较大者:#define max(a, b) ____

答案((a) > (b) ? (a) : (b))解析:利用三元运算符实现,为避免宏展开时的优先级问题,给 a 和 b 都加上括号。

题目 2

用预处理指令#define声明一个常数,用以表明一年中有多少秒(忽略闰年问题):#define ____

答案ONE_YEAR_SECONDS (365 * 24 * 60 * 60)解析:一年 365 天,每天 24 小时,每小时 60 分钟,每分钟 60 秒,通过乘法计算总秒数。

题目 3

下面代码包括 2 个函数,第一个函数是中断服务程序用于从温度传感器中读取数据,第二个函数用于比较温度是否一致。它是否包括错误?如有,该如何修正?

static int __g_temperatures[2];__interrupt void isr_temperatures_read (void)
{__g_temperatures[0] = temperature_sensor1_read(); /* Get Temperature from Sensor 1 */__g_temperatures[1] = temperature_sensor2_read(); /* Get Temperature from Sensor 2 */
}void main (void)
{while (1) {if (__g_temperatures[0] != __g_temperatures[1]) {;/* Alarm */}}
}

答案:存在错误。问题分析:在中断服务程序和主程序之间共享全局变量__g_temperatures时,没有做原子操作保护,可能导致数据竞争(主程序读取时,中断程序可能正在修改数组元素)。修正方法:添加一个 ** volatile 类型的标志位或使用互斥机制 **(如关中断保护)来确保数据读取的原子性。例如:

static volatile int __g_temperatures[2];
static volatile int flag = 0;__interrupt void isr_temperatures_read (void)
{__g_temperatures[0] = temperature_sensor1_read();__g_temperatures[1] = temperature_sensor2_read();flag = 1; // 标记数据已更新
}void main (void)
{while (1) {if (flag) {flag = 0; // 重置标志if (__g_temperatures[0] != __g_temperatures[1]) {;/* Alarm */}}}
}

题目 4

请给下面代码段中的变量按存放位置(指针变量指的是指针指向的内存)进行归类:

static int static_int;
int  public_int;
int  initialized = 4;
  • 只读存储:____
  • 可读写存储:____
  • 堆:____
  • 栈:____

答案

  • 只读存储:无(本题变量均为可读写)
  • 可读写存储:static_intpublic_intinitialized
  • 堆:无(本题无动态内存分配)
  • 栈:无(本题变量为全局 / 静态变量,非栈上的局部变量)解析static_int是静态全局变量,存放在可读写的静态存储区;public_intinitialized是全局变量,也存放在可读写的静态存储区。栈用于存放函数局部变量、函数参数等,堆用于动态内存(如malloc分配),本题无对应场景。


宏定义解释

  • 对于第一段宏定义代码:

    • static const u16_t memp_sizes[] = {
    • #define MEMPOOL(name,num,size,desc) (size),
    • #include "std.h"
    • };这段代码的作用是定义一个存储内存池块大小的数组 memp_sizes。当包含头文件 std.h 时,其中的 MEMPOOL 宏会被展开为对应的 size(内存块大小),从而将各个内存池的块大小依次填入 memp_sizes 数组中。例如 MEMPOOL(B_PCB,3,30,"B_PCB") 会将 30 作为一个元素加入该数组。
  • 对于第二段宏定义代码:

    • static u8_t memp_memory[3
    • #define MEMPOOL(name,num,size,desc) + ((num) * (size))
    • #include "std.h"
    • };这段代码的作用是定义一个存储内存池实际内存的数组 memp_memoryMEMPOOL 宏在这里展开为 (num) * (size)(内存块数量乘以每个块的大小),从而计算出该内存池所需的总内存大小,多个内存池的内存大小累加后确定 memp_memory 数组的总长度,用于分配内存池的实际存储区域。

链表摘除节点函数补充

函数用于从链表中摘除指定节点,补充后的完整代码如下:

typedef void **list_t;struct list {struct list *next;
};void list_remove (list_t list, void *item)
{struct list *l, *r;if (*list == NULL) {return;}r = NULL;for (l = *list; l != NULL; l = l->next) {if (l == item) {if (r == NULL) {*list = l->next; // 摘除头节点时,更新链表头指针} else {r->next = l->next; // 摘除中间或尾节点时,更新前驱节点的next指针}l->next = NULL;return;}r = l; // 保存当前节点作为下一个节点的前驱}
}

解析

  • 变量 r 用于保存当前节点 l 的前驱节点。
  • 当找到要摘除的节点 item(即 l == item)时:
    • 若 r == NULL,说明要摘除的是头节点,此时需要将链表头指针 *list 更新为 l->next
    • 若 r != NULL,说明要摘除的是中间或尾节点,此时将前驱节点 r 的 next 指针指向 l->next,即可跳过当前节点 l
    • 最后将 l->next 置为 NULL,完成节点摘除并返回。


问题 5:多任务调用计数器函数的问题及解决

原代码

static int __g_counter;
os_semaphore_t __g_sem_plus;
os_semaphore_t __g_sem_minus;void counter_increment(int count)
{os_semaphore_take(__g_sem_plus);__g_counter += count;os_semaphore_give(__g_sem_plus);
}void counter_decrement(int count)
{os_semaphore_take(__g_sem_minus);__g_counter -= count;os_semaphore_give(__g_sem_minus);
}

问题分析:全局变量__g_countercounter_incrementcounter_decrement两个函数共享,但分别使用__g_sem_plus__g_sem_minus两个不同信号量保护。当多任务(A、B、C)同时调用这两个函数时,可能导致__g_counter的读写冲突(例如:一个任务执行+count时,另一个任务同时执行-count,导致计数结果错误)。

解决方法:使用同一个信号量__g_counter的所有操作进行互斥保护,确保每次只有一个任务能修改计数器。修改后代码:

static int __g_counter;
os_semaphore_t __g_sem_counter; // 统一的互斥信号量void counter_increment(int count)
{os_semaphore_take(__g_sem_counter); // 获取锁__g_counter += count;os_semaphore_give(__g_sem_counter); // 释放锁
}void counter_decrement(int count)
{os_semaphore_take(__g_sem_counter); // 获取锁__g_counter -= count;os_semaphore_give(__g_sem_counter); // 释放锁
}

问题 6:字符接收与处理任务的错误分析

原代码逻辑

  • 任务 1(task_get_characters):接收字符,按紧急程度投递到URGENT_QUEUE(紧急队列)或NORMAL_QUEUE(普通队列)。
  • 任务 2(task_consume_characters):死循环中先从紧急队列取字符(os_queue_pend(URGENT_QUEUE, WAIT_FOREVER)),再从普通队列取字符(os_queue_pend(NORMAL_QUEUE, WAIT_FOREVER))。

错误指出:任务 2 会导致普通队列的字符可能永远无法被处理。原因是:os_queue_pend(URGENT_QUEUE, WAIT_FOREVER)表示 “无限等待紧急队列的字符”,若紧急队列长期无数据,任务 2 会一直阻塞在该语句,即使普通队列有字符也无法处理(普通队列被 “饿死”)。

修正思路:对紧急队列使用有限超时等待(如os_queue_pend(URGENT_QUEUE, 10),超时 10 个时间单位),超时后立即检查普通队列,确保普通队列能被轮询到。

问题 7:32 位 CPU 下结构体成员偏移量计算

代码

#define offsetof(type, member) ((size_t)&((type*)0)->member)typedef struct a_struct {char ch;short data;long value;void *buf;
} a_struct;int main(void)
{printf("%d, %d, %d, %d\n",offsetof(a_struct, ch),offsetof(a_struct, data),offsetof(a_struct, value),offsetof(a_struct, buf));
}

能否正常工作:能正常工作。打印结果0, 2, 4, 8

解析(32 位 CPU 对齐规则):

  • ch(char):首成员,偏移 0 字节(1 字节大小)。
  • data(short):需 2 字节对齐,ch占 1 字节,补 1 字节填充(padding),故偏移 2 字节(2 字节大小)。
  • value(long):需 4 字节对齐,前两个成员总占用 4 字节(1+1+2),故偏移 4 字节(4 字节大小)。
  • buf(void*):需 4 字节对齐,value占 4 字节(偏移 4~7),故偏移 8 字节(4 字节大小)。
http://www.dtcms.com/a/580888.html

相关文章:

  • AI搜索营销破局:光引GEO多平台适配与实时优化引擎开发详解
  • 【有源码】基于Hadoop+Spark的起点小说网大数据可视化分析系统-基于Python大数据生态的网络文学数据挖掘与可视化系统
  • Windows10 wsl2 ubuntu22.04 docker安装
  • 使用docker-compose部署应用保姆级教程
  • 【Linux工具链】从跨平台适配到一键部署:yum多架构支持+Vim远程编辑+gcc交叉编译,解决多场景开发效率瓶颈
  • 简单做网站企业宣传视频制作免费模板
  • 西安SEO网站建设哪家好食品网站的网页设计
  • 网站开发公司哪家好嘉兴市建设工程监理协会网站
  • 天津做一个简单的网站首页wap门户网站源码
  • 热门软件排行榜泰州网站关键词优化
  • 怎么查询网站开发公司个人网站数据库大小
  • 营销型网站和传统网站区别ui设计技能就业培训
  • 威宁住房和城乡建设局网站wordpress is ssl
  • 网站域名缴费wordpress怎么改登陆地址
  • 网站底备案号链接代码小程序登录入口qq浏览器
  • 电商网站建设功能个人网页免费域名注册入口
  • 网站建设所用系统没有文字的网站怎么优化
  • 站长工具seo综合查询隐私查询做网站功能
  • 扬州市广陵区建设局网站做代理稳妥的彩票网站有哪些
  • 软件下载类型网站怎么做建筑公司资质甲级乙级
  • 自己建站百度企业查询官网
  • 如皋建设网站wordpress中级教程
  • 正规轻电商网站模板做美足网站违法吗
  • 可以做本地生活服务的有哪些网站平面设计作品欣赏官网
  • 专业网站托管的公司免费咨询医院
  • 温州哪里有做网站怎么查公司企业邮箱
  • 什么叫网站维护整站优化提升排名
  • 广东联通通信建设有限公司 网站王烨画家
  • 金属网站模板石家庄做网站公司
  • 英文网站网站建设深圳网站备案