全局变量和静态变量的区别
在嵌入式开发中,理解变量的作用域和存储位置至关重要。全局变量的作用域贯穿整个程序,而局部变量仅限于当前函数或代码块。从内存角度看,全局变量(包括静态全局和静态局部变量)分配在全局数据区(静态存储区),而普通局部变量则位于栈区。生命周期上,全局变量随程序启动创建、结束销毁,局部变量则随函数调用入栈出栈。使用方式上,全局变量可跨文件访问(需声明),局部变量仅限内部使用。
全局变量能否定义在头文件中
可以,但需谨慎。若要在多个 .c 文件中共享同名全局变量,必须在头文件中声明,且只能在一个 .c 文件中初始化。否则链接时会报错重复定义。
局部变量与全局变量重名
允许重名。局部变量会屏蔽同名的全局变量。编译器优先查找局部作用域内的符号。甚至在同一个函数的不同循环体内也可以定义同名的局部变量,它们的作用域仅限于各自的循环块内。
析构函数为何必须是虚函数
当通过基类指针删除派生类对象时,如果基类析构函数不是虚函数,只会调用基类的析构函数,导致派生类特有的资源(如动态分配的内存)未被释放,引发内存泄漏。因此,所有可能被继承的基类都应声明虚析构函数。
C++ 默认析构函数非虚的原因
为了节省内存开销。虚函数需要虚函数表(vtable)和虚表指针(vptr),这会占用额外的空间。对于不会被继承的类,开启虚析构函数纯属浪费。只有当类设计为基类使用时,才应将其设为虚函数。
静态函数与虚函数的区别
静态函数在编译期绑定,直接调用,无多态性;虚函数在运行期动态绑定,依赖虚函数表机制,支持运行时多态,但会带来微小的性能开销。
重载与覆盖的区别
覆盖(Override)是子类重写父类方法,属于垂直关系,要求签名一致;重载(Overload)是同一类中方法名相同但参数列表不同,属于水平关系,由编译器根据实参类型解析。
虚函数表实现多态原理
每个包含虚函数的类都有一个虚函数表,存放虚函数地址。对象实例中包含指向该表的指针。当通过基类指针调用虚函数时,程序通过 vptr 找到 vtable,再根据偏移量调用实际函数地址。若子类重写了虚函数,vtable 中对应项会被替换,从而实现多态。
C 语言函数调用机制
CPU 通常使用栈帧来支持函数调用。栈用于传递参数、保存返回地址、临时寄存器及局部变量。每个函数调用生成一个栈帧,由帧指针(ebp)和栈指针(esp)管理。帧指针指向栈帧头部(上一个栈帧地址),栈指针指向栈顶。
select 函数详解
select 是多路复用 IO 模型的一种实现。
- 原型:
int select(int maxfdp, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout); - 限制: 单个进程监视的文件描述符上限通常为 1024(取决于内核配置)。
- 轮询效率:
select返回就绪 FD 数量后,应用层需遍历所有 FD 判断状态。FD 越多,性能越差。 - 拷贝开销: 每次调用都需将 FD 集合从用户态拷贝到内核态,开销较大。
- 触发方式: 水平触发。只要 FD 未读完,下次
select仍会通知。 - 优缺点: 优点是跨平台性好,超时精度可达微秒;缺点是 FD 数量有限,遍历和拷贝开销大。
fork, wait, exec 函数
这三个函数常用于进程控制。


