
大厂面试题:一,static关键字及作用1,修饰局部变量:不再存放在栈区,放在静态存储区;只在第一次调用时初始化一次。函数退出后变量值保留,生命周期等于整个程序2,修饰全局变量:改变作用域,进当前.c源文件内可见,其他文件无法通过extern引用,主要避免全局冲突3,修饰函数:函数作用域限定为本文件,外部文件不能调用,用于封装模块内部接口二,volatile关键字volatile作用:告诉编译器,该变量随时可能被外部修改,禁止编译器做寄存器缓存优化,每次读写必须从内存地址直接操作,不能使用寄存器里缓存的旧值三,MCU的主频是什么,开发板的架构MCU主频:内核工作时钟频率,代表内核每秒执行指令的基础时钟。例如STM32F1最高72MHz,F4 168MHZ,H7 400MHZ,英飞凌的TC264是双核200MHZ。主频越高,理论运算速度越快;但功耗,发热上升开发板架构:常用STM32是ARM Cortex-M系列,属于RISC精简指令集,哈佛总线架构哈佛总线架构:指令总线和数据总线分离,可以同时取指令,读写数据,相比冯诺依曼架构效率更高四,中断和轮询的区别轮询:CPU持续循环查询标志位,判断事件是否到来。程序主动检查优点:逻辑简单,无上下文切换开销;缺点:持续占用CPU,浪费算力,实时性差中断:硬件外设触发信号,通知CPU。CPU正常跑主程序;事件触发时暂停当前代码,保存现场,跳转到中断服务函数ISR处理,处理完恢复现场继续运行优点:CPU利用率高,事件响应实时性好;缺点:存在上下文压栈开销;中断嵌套,共享数据处理不当会引发bug五,FreeRTOS调度机制FreeRTOS不同优先级使用抢占式调度,相同优先级使用时间片轮转1,抢占式:一旦有更高优先级任务变为就绪态,立刻抢占CPU,低优先级任务暂停,高优先级马上运行2,时间片轮转:多个同优先级就绪任务,每个任务分配固定时间片,时间片耗尽切换到同优先级下一个任务3,低优先级任务只有在更高优先级任务进入阻塞态时,才有机会执行六,FreeRTOS提供5种任务间通信:1,队列:核心数据传递机制,把数据拷贝存入队列,支持任务-任务,中断-任务传递数据;支持多写多读2,二值信号量:事件同步,标记事件有没有发生,适合中断通知任务。3,计数信号量:资源计数,记录可用资源数量4,互斥量,共享资源保护,自带优先级继承,防止优先级反转。中断上下文禁止使用5,事件组:多个事件位,可以等待多个事件任意一个七,有没有遇到堆栈溢出的情况,怎么处理的项目里遇到过任务栈溢出问题主要原因:1,任务栈分配尺寸太小2,函数内部定义超大局部数组(局部变量存栈)3,函数递归调用深度过大4,中断嵌套过深,占用任务栈5,函数内大量临时局部变量排查方法:1,使用uxTaskGetStackHighWaterMark()获取任务栈历史最小剩余空间,看剩余容量2,开启FreeRTOS栈溢出钩子函数vApplicationStackOverflowHook,溢出时进入钩子,可打印任务信息3,调试器查看栈内存,看栈顶标记是否被覆盖解决方法1,适当调大对应任务栈大小2,大数组不要作为局部变量,改成static静态变量,全局变量或者堆内存分配3,取消递归,改用循环;拆分长函数,减少栈内临时变量4,把中断栈独立配置,不和任务栈公用专题类:一,指针与内存1,什么是指针?指针变量占用多少内存指针是一个变量,存储的是另一个变量的地址32位系统:指针占用4字节64位系统:指针占用8字节指针大小与所指向的数据类型无关2,*p++和(*p)++有什么区别*p++等价于*(p++),先取值,后移动指针(*p)++先取值,对取到的值进行自增++*p等价于++(*p),对指针指向的值自增*++p等价于*(++p),先移动指针,再取值3,数组名和指针有什么区别数组名:(1)是常量,不能修改 (2)sizeof返回的是整个数组大小 (3)arr获取整个数组地址 (4)数组名不占用额外存储空间,数组的内存,存的是数组里面的元素指针变量:(1)是变量,可以修改 (2)sizeof返回指针大小 (3)p获取指针变量地址 (4)占用4/8字节空间4,如何理解多维数组的指针操作例 int arr[3][4]二维数组arr:指向第一行的指针arr+1:指向第二行*(arr + 1)第二行首元素地址*(arr + 1) + 2 第二行第三个元素地址*(*(arr + 1)+ 2)第二行第三个元素值5,函数指针和指针函数有什么区别函数指针:(1)指向函数的指针 (2)int(*p)(int,int) (3)用于回调函数,状态机等 (4)实现多态和动态调用eg:int add(int a,int b){return a+b;} int (*p)(int,int); p = add; // 函数名本身就是函数入口地址 int res = p(1,2); // 通过函数指针调用函数指针函数:(1)返回指针的函数 (2)int * func(int,int) (3)可返回数组或字符串6,野指针和空指针有什么区别野指针:(1)指向未知区域 (2)访问可能崩溃或数据损坏 (3)难以调试和发展 (4)造成内存泄漏空指针:(1)指向NULL(0) (2)访问会立即崩溃 (3)容易调试和发展 (4)安全的初始状态7,内存四区代码区(.text),全局区,栈区,堆区代码区:存放程序二进制指令,只读,程序运行前就加载。存放机器码(源码 C → 编译 → 汇编指令→ 汇编器 →机器码),常量,字符串全局区(data段+bss段,静态存储区):data段:已初始化全局变量,static静态变量bss段:未初始化全局变量,static静态变量栈区:函数局部变量,函数形参,函数返回地址,函数在调用时自动分配,函数退出自动释放堆区:malloc/calloc/realloc手动申请,free手动释放8,什么是RAM,什么是ROM,和内存区的关联与区别ROM:只读存储器(Read Only Memory),掉电不丢失的数据,存放代码段,程序镜像(bin/hex 文件)烧写在这里RAM:随机存储存储器(Random Access Memory),掉电数据丢失,程序运行时临时读写,存放全局段,堆,栈区别:ROM/RAM 是硬件存储器;内存四区是编译器对程序的分段,是软件逻辑上的划分9,栈和堆的区别栈自动释放,堆手动管理对比项 栈 Stack 堆 Heap 分配释放 编译器自动管理,函数进入分配、退出自动回收 程序员手动malloc / free 空间大小 容量很小(MCU通常几KB~几十KB) 空间大,嵌入式RTOS可配置堆大 小 增长方向 向下增长(地址变小) 向上增长(地址变大) 速度 读写速度快,CPU直接支持