移远通信 嵌入式软件开发 一面
1. ARM处理器是什么架构?Cortex-M和Cortex-A系列有什么区别?
答案:
- ARM是RISC(精简指令集)架构
- Cortex-M系列:面向微控制器,功耗低,实时性强,适合嵌入式控制(如Cortex-M7、M4)
- Cortex-A系列:面向应用处理器,性能强,支持MMU和操作系统(如Cortex-A53、A72)
2. 堆和栈的主要区别是什么?
答案:
- 栈(Stack):由编译器自动分配释放,存放局部变量、函数参数,生长方向向下(高地址→低地址),空间较小(通常几MB)
- 堆(Heap):由程序员手动分配释放(malloc/free),空间较大,生长方向向上(低地址→高地址),容易产生内存碎片
3. 如何判断栈的增长方向?
答案:
void check_stack_direction() {
int a;
int b;
if (&b < &a) {
printf("栈向下增长\n"); // 大多数系统
} else {
printf("栈向上增长\n");
}
}
4. const修饰的变量存储在内存的哪个区域?
答案:
- const全局变量:存储在只读数据段(.rodata)
- const局部变量:存储在栈上
- const指针:取决于const修饰的是指针还是指向的内容
5. 线程和进程有什么区别?
答案:
- 进程:资源分配的基本单位,拥有独立的地址空间,进程间切换开销大
- 线程:CPU调度的基本单位,共享进程的地址空间和资源,线程间切换开销小
- 一个进程可以包含多个线程
6. 如何创建一个新进程?fork()函数的返回值是什么?
答案: 使用fork()系统调用创建进程:
- 返回值 > 0:在父进程中,返回子进程PID
- 返回值 = 0:在子进程中
- 返回值 < 0:创建失败
pid_t pid = fork();
if (pid == 0) {
// 子进程代码
} else if (pid > 0) {
// 父进程代码
} else {
// 错误处理
}
7. fork创建子进程后,父子进程哪些资源是共享的?
答案:
- 共享:代码段、打开的文件描述符、信号处理函数
- 不共享(复制):数据段、堆、栈、进程ID、父进程ID
8. 指针变量的大小是多少?用什么运算符获取?
答案:
- 32位系统:4字节
- 64位系统:8字节
- 使用
sizeof()运算符获取大小 - 指针大小与指向的数据类型无关,只与系统位数有关
9. '\0'的十六进制表示是什么?
答案:
- '\0' 的十六进制表示是 0x00
- 它是字符串的结束标志(NULL字符)
10. 如何将一个16位数的最低位置0或置1?
答案:
uint16_t data = 0x1234; // 最低位置0 data &= 0xFFFE; // 或 data &= ~0x0001; // 最低位置1 data |= 0x0001;
11. 什么是虚拟地址?为什么需要虚拟地址?
答案:
- 虚拟地址是程序使用的逻辑地址,通过MMU映射到物理地址
- 优点:进程隔离,提高安全性简化内存管理支持内存保护允许使用比物理内存更大的地址空间
12. platform驱动框架和misc设备框架的区别?
答案:
- Platform框架:用于总线设备驱动,支持设备树,实现设备和驱动分离
- Misc框架:用于简单字符设备,自动分配次设备号(主设备号固定为10),适合简单设备
13. 字符设备驱动中file_operations结构体包含哪些常用接口?
答案:
struct file_operations {
.open = xxx_open, // 打开设备
.release = xxx_release, // 关闭设备
.read = xx
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
嵌入式面试八股文全集 文章被收录于专栏
这是一个全面的嵌入式面试专栏。主要内容将包括:操作系统(进程管理、内存管理、文件系统等)、嵌入式系统(启动流程、驱动开发、中断管理等)、网络通信(TCP/IP协议栈、Socket编程等)、开发工具(交叉编译、调试工具等)以及实际项目经验分享。专栏将采用理论结合实践的方式,每个知识点都会附带相关的面试真题和答案解析。
