嵌入式 C/C++ 核心知识点梳理
变量与存储机制
全局变量和静态变量的区别
理解这两者的差异是掌握内存管理的基础:
- 作用域:全局变量的作用域通常跨越整个程序(除非被 static 修饰),而局部变量的作用域仅限于当前函数或代码块。
- 存储位置:全局变量(包括静态全局变量和静态局部变量)分配在全局数据区(静态存储空间);局部变量则分配在栈区。
- 生命周期:全局变量随主程序创建而创建,随主程序销毁而销毁;局部变量仅在函数或循环体执行期间存在,退出即释放。
- 使用方式:全局变量通过声明可在程序各处访问,局部变量仅限局部使用。
全局变量定义在头文件中
可以在多个 .c 文件中包含同一个头文件来声明全局变量,但必须注意链接规则:
- 如果希望变量在所有文件中共享同一份内存,头文件中应只声明
extern,而在其中一个.c文件中定义并初始化。 - 如果需要在每个
.c文件中拥有独立的同名变量,则必须在头文件中将其声明为static。此时连接不会出错,因为每个编译单元都有独立的副本。
局部变量与全局变量重名
局部变量可以与全局变量同名。在函数内引用时,编译器会优先匹配同名的局部变量,从而屏蔽全局变量。对于某些编译器,甚至允许在同一个函数的不同作用域(如两个嵌套循环)中定义同名的局部变量,其作用域严格限制在该作用域内。
C++ 面向对象机制
析构函数与虚函数
为什么析构函数必须是虚函数? 当通过基类指针删除派生类对象时,如果基类的析构函数不是虚函数,只会调用基类的析构函数,导致派生类部分资源未被释放,引发内存泄漏。将父类析构函数设为虚函数,可确保运行时正确调用子类的析构函数。
为什么默认不是虚函数? C++ 默认析构函数非虚,是因为虚函数需要额外的虚函数表(vtable)和虚表指针(vptr),这会占用额外内存。对于不会被继承的类,设置虚析构函数纯属浪费。因此,只有当类设计为可能被继承且需多态删除时,才显式声明为虚函数。
C++ 析构函数的作用 析构函数用于对象销毁前的清理工作,例如关闭打开的文件、释放动态分配的内存等。它自动完成'扫尾'任务,无需手动调用其他成员函数。
静态函数与虚函数
- 绑定时机:静态函数在编译期确定运行地址(静态绑定);虚函数在运行期动态绑定。
- 开销:虚函数因涉及虚函数表查找,调用时会增加一次间接寻址的内存开销。
重载与覆盖的区别
- 关系维度:覆盖(Override)是子类与父类之间的垂直关系;重载(Overload)是同一类中方法之间的水平关系。
- 数量约束:覆盖通常是一对一的方法对应;重载涉及多个同名方法。
- 选择依据:覆盖根据对象实际类型决定;重载根据调用时的实参列表(参数类型和数量)决定。
虚函数表实现多态
原理:每个类维护一个虚函数表,存放虚函数地址。对象创建时包含指向该表的指针。当子类重写父类虚函数时,表中对应地址会被替换为子类函数地址。 作用:通过基类指针调用成员函数时,虚函数表能准确指明实际调用的具体函数版本,从而实现运行时多态。
系统编程基础
C 语言函数调用与栈帧
大多数 CPU 使用栈支持函数调用。栈用于传递参数、存储返回地址、保存寄存器状态及局部变量。每个函数调用生成一个栈帧(Stack Frame),由帧指针(Frame Pointer, 通常 ebp)和栈指针(Stack Pointer, 通常 esp)界定。
注:此处通常展示栈帧结构示意图,包含帧指针指向栈帧头部(上一个栈帧地址),栈指针指向栈顶。


