一、makefile链接库参数
LIBS = -L/path/to/lib -lmyliball: myprogrammyprogram: myprogram.ogcc -o myprogram myprogram.o $(LIBS)myprogram.o: myprogram.cgcc -c myprogram.c
二、shell指令
- Shell指令通常指的是在Linux及Unix系统的命令行界面中使用的命令。
- 常用指令
ls:列出当前目录中的文件和文件夹。
cd:更改当前工作目录。
pwd:显示当前工作目录的完整路径。
mkdir:创建新目录。
rmdir:删除空目录。
rm:删除文件或目录(rm -r可递归删除)。
cp:复制文件或目录。
mv:移动或重命名文件或目录。cat:显示文件内容。
more:分页显示文件内容。
less:比more更强大的分页查看工具。
head:显示文件的前几行。
tail:显示文件的最后几行。top:实时显示系统进程和资源使用情况。
ps:显示当前运行的进程。
df:显示文件系统的磁盘空间使用情况。
du:显示目录或文件的磁盘使用情况。
三、gcc优化等级
- 默认不优化,基础三个优化,拓展2个
- 范例
gcc -O0 example.c -o example_O0
gcc -O1 example.c -o example_O1
gcc -O2 example.c -o example_O2
gcc -O3 example.c -o example_O3
gcc -Os example.c -o example_Os
gcc -Ofast example.c -o example_Ofast
四、守护进程怎么开启
- 在Linux中,守护进程(daemon)是一种在后台运行的进程,通常用于提供系统服务。
- 开启守护进程
sudo systemctl start 服务名
sudo systemctl start ssh
- 自己创建守护进程
五、孤儿进程
- 没有父进程的进程。父进程退出,子进程不退出,此时子进程就是孤儿进程
- 孤儿进程会被init进程(1号进程)收养。
- 孤儿进程运行在后端,脱离终端控制
- 孤儿进程是活着的进程,没有危害
六、如何判断一个链表有环
- 快慢指针法
- 定义两个指针:一个慢指针slow每次移动一步,一个快指针fast每次移动两步。
- 遍历链表:
如果fast和fast->next都不为NULL,则继续移动指针。
如果slow和fast相遇,说明链表有环。
如果fast指针到达NULL,说明链表没有环。
七、二叉树和二叉搜索树的区别
- 二叉搜索树(BST),是一种特定类型的二叉树,满足以下性质:
- 对于每个节点,左子树中所有节点的值都小于该节点的值。
- 右子树中所有节点的值都大于该节点的值。
- 这种特性使得搜索、插入和删除操作的时间复杂度为O(log n)
八、堆和栈的区别
- 内存分配方式
栈(Stack):内存由系统自动管理,采用后进先出(LIFO)的方式。
主要用于存储局部变量和函数调用信息。
分配和释放速度快,生命周期由作用域决定。
堆(Heap):内存由程序员手动管理,需要使用动态内存分配(如malloc、free等)。
适用于需要动态分配大小的对象,如数组、链表等。
分配和释放速度较慢,生命周期由程序员控制。
- 存储方式
栈:通常在内存的高地址区域,随着函数调用的嵌套而向下增长。
栈的大小通常有限,过多的递归调用可能导致栈溢出。堆:通常在内存的低地址区域,分散分配,随着程序运行而动态变化。
堆的大小受限于可用内存,通常比栈大。
- 生命周期
栈:
变量在其作用域结束时自动释放,无法手动控制。
堆:
变量必须手动释放,忘记释放可能导致内存泄漏。
- 适用场景
栈:
适合于临时变量和函数调用,自动管理内存。堆:
适合于需要动态存储的对象,如大型数据结构、对象等。
九、函数指针和指针函数的区别
- 函数指针是指向函数的指针,用于调用函数。
- 指针函数是返回指针的函数,用于返回指向某种类型的数据的指针。
十、文件IO 0 1 2分别表示什么
- 文件描述符(file descriptor)是指向打开文件的整数标识符。
- 0 - 标准输入(stdin)
- 1 - 标准输出(stdout)
- 2 - 标准错误(stderr)
- 可以通过重定向和管道使用这些文件描述符。
十一、多进程多线程的区别
- 资源分配,稳定性,应用场景
- 应用场景
多进程:
适合 CPU 密集型任务(如大数据处理),以及需要隔离的任务(如运行不同的应用程序)。多线程:
适合 I/O 密集型任务(如网络请求、文件操作),需要频繁通信的场景。
十二、什么是临界区
- 临界区是指在并发编程中,多个线程或进程访问共享资源时,可能导致数据不一致的代码区域。由于这些资源(如变量、数据结构或设备)只能被一个线程或进程在同一时间安全地访问,因此临界区需要通过同步机制来控制访问。
十三、怎么保护临界区的
- 互斥锁
- 信号量
- 读写锁
- 原子操作
- 禁用中断
十四、IO多路复用
- select是最早的I/O多路复用机制,允许程序监视多个文件描述符,检查哪些文件描述符准备就绪进行读、写或异常处理。支持的文件描述符数量有限
- poll是对select的改进,支持更多的文件描述符,不再有数量限制。仍然需要每次调用传递文件描述符集合,效率较低。
- epoll在处理大量连接时比select和poll更高效,特别是在高并发场景下,避免了遍历所有描述符的开销。
十五、在大工程中一个makefile如何包含其他的makefile
- 使用 include 指令
在主makefile中,可以使用include指令来包含其他的makefile。语法如下:
include other_makefile.mk
十六、shell中如何检测一条指令正常执行
- 可以通过检查上一个命令的返回值来检测一条指令是否正常执行。每个命令在执行后都会返回一个状态码,通常称为退出状态(exit status)
command
if [ $? -eq 0 ]; thenecho "命令成功执行"
elseecho "命令执行失败"
fi
十七、 用Shell判断一个文件是否存在
if [ -e filename ]; thenecho "文件存在"
elseecho "文件不存在"
fi
十八、GDB是什么
- GDB(GNU Debugger)是GNU项目提供的一个调试工具,用于调试C、C++等语言编写的程序。它允许开发者在程序运行时查看和控制程序的执行,帮助定位和修复错误。
- 主要功能
设置断点:可以在特定行或函数设置断点,程序运行到该位置时会暂停。
查看变量:可以查看和修改程序中的变量值。
步进执行:可以逐行执行代码,观察程序的运行状态。
堆栈跟踪:可以打印调用堆栈,帮助理解程序的执行流程。
多线程支持:可以调试多线程程序,查看各线程的状态。
十九、u-boot的启动流程
- 上电复位
- 初始化硬件
- 加载U-Boot
- 运行U-Boot
- 启动操作系统
- 传递控制权
二十、IIC有几根线
- I2C(Inter-Integrated Circuit)通常使用两根线:
SDA(数据线):用于传输数据。
SCL(时钟线):用于提供时钟信号。
二十一、 有33层楼3部电梯,怎么利用率最大
- 分区调度:将每部电梯分配到特定的楼层范围。例如:
电梯A服务1-11层
电梯B服务12-22层
电梯C服务23-33层 - 优先级设置
二十二、5个海盗分100金币,一半同意就可以执行海盗的分配策略,否则该海盗被杀死,第二个海盗继续分配,依次内推
A:90金币
B:1金币
C:4金币
D:2金币
E:3金币
二十三、MMU是什么
- MMU(Memory Management Unit,内存管理单元)是计算机系统中的一个硬件组件,负责管理内存的分配和访问。
- 它在操作系统与硬件之间起到桥梁的作用,提供内存保护、地址转换和虚拟内存等功能。
二十四、中断的详细过程
1. 中断产生
2. 中断识别
3. 保存上下文
4. 中断向量
5. 切换到对应的中断服务程序
6. 处理中断
7. 恢复上下文
8. 返回主程序
二十五、动静库如何创建
- 创建静态库
gcc -c example.c -o example.o
ar rcs libexample.a example.o
- 创建动态库
gcc -fPIC -shared example.c -o libexample.so
编译 example.c 文件,生成一个位置无关的共享库 libexample.so。这个库可以在运行时被其他程序动态加载和使用。
二十六、编译的可执行文件以什么结尾
- Linux和Unix
- 可执行文件通常没有特定的扩展名,可以直接使用文件名,例如 my_program。
- 也可以用 .out 结尾,例如 my_program.out,但这不是强制要求。
- Windows
- 可执行文件以 .exe 结尾,例如 my_program.exe。
- macOS
- 在macOS中,可执行文件同样没有特定的扩展名,但通常也可以用 .app 目录来表示应用程序。
二十七、程序冗余的解决办法
- 函数抽象:将重复的代码块提取到函数中,避免重复代码。
- 使用库或框架:利用已有的库或框架,减少手动编写的代码。
- 代码重构:定期检查和重构代码,消除冗余。
- 遵循设计模式:使用适当的设计模式可以有效减少冗余。
二十八、 TCP 粘包
- TCP 粘包是指在使用 TCP 协议传输数据时,发送方的多个数据包被接收方合并为一个数据包,导致接收方无法分辨数据包的边界。
- 解决办法:定长消息、头部字段、分隔符等。
二十九、互斥锁实现原理
- 互斥锁用于控制对共享资源的访问,避免数据竞争。其实现原理通常包括
- 锁的状态:记录锁的状态(如空闲或被占用)
- 原子操作:使用原子操作来改变锁状态,确保不会出现竞态条件
- 线程调度:当锁被占用时,其他线程会被阻塞,直到锁释放
三十、STM32 的 GPIO 几种模式
- 输入模式:用于接收外部信号。
- 输出模式:用于输出信号。
- 复用功能模式:用于将 GPIO 引脚配置为特定外设的功能(如 UART、I2C)。
- 模拟模式:用于模拟信号处理。