联想嵌入式软件开发 一面 面经(常规问题居多)
1.自我介绍
面试官好,我是[姓名],[学校][专业][年级]。我的技术方向是嵌入式开发,主要使用C++。
技术栈方面,我熟悉C++语言特性、STL容器、多线程编程,了解Linux系统和嵌入式开发。有实际的项目经验,做过智能系统开发,涉及到模型部署、性能优化等工作。
我对嵌入式开发很感兴趣,特别是资源受限环境下的软件优化。联想在PC和智能设备领域有很强的技术实力,希望能加入贵公司,在嵌入式方向深入发展。
2.说说C++中的多态,静态多态和动态多态有什么区别?
多态是面向对象的重要特性,指同一个接口可以有不同的实现方式。C++中有两种多态:静态多态和动态多态。
静态多态是编译期确定的,主要通过函数重载和模板实现。编译器根据参数类型或模板参数,在编译时就确定调用哪个函数,没有运行时开销。
// 函数重载实现静态多态
void print(int x) {
cout << "int: " << x << endl;
}
void print(double x) {
cout << "double: " << x << endl;
}
// 模板实现静态多态
template<typename T>
void print(T x) {
cout << x << endl;
}
// 编译时确定调用哪个版本
print(10); // 调用print(int)
print(3.14); // 调用print(double)
动态多态是运行期确定的,通过虚函数和继承实现。基类指针或引用可以指向派生类对象,调用虚函数时,根据对象的实际类型决定调用哪个版本。这是通过虚函数表(vtable)实现的,有一定的运行时开销。
class Base {
public:
virtual void show() {
cout << "Base" << endl;
}
};
class Derived : public Base {
public:
void show() override {
cout << "Derived" << endl;
}
};
// 运行时确定调用哪个版本
Base* ptr = new Derived();
ptr->show(); // 输出"Derived",运行时根据实际类型决定
区别总结:
- 静态多态在编译期确定,效率高,没有运行时开销
- 动态多态在运行期确定,灵活性高,但有虚函数表查找的开销
- 静态多态通过重载和模板,动态多态通过虚函数
- 嵌入式开发中,如果追求性能,优先用静态多态
3.inline关键字的作用是什么?什么时候使用?
inline关键字建议编译器将函数内联展开,即在调用处直接插入函数代码,而不是通过函数调用。这样可以减少函数调用的开销(保存寄存器、跳转、返回等),提高性能。
inline int add(int a, int b) {
return a + b;
}
int main() {
int result = add(3, 5); // 编译器可能展开为:int result = 3 + 5;
}
inline的特点:
- 只是建议,编译器可以忽略。复杂的函数(如有循环、递归)通常不会内联
- 内联函数的定义通常放在头文件中,因为编译器需要看到完整定义才能内联
- 内联会增加代码体积,如果函数被多次调用,会有多份代码拷贝
- 类内定义的成员函数默认是inline的
使用场景:
- 函数体很小,只有几行代码
- 函数被频繁调用,在性能关键路径上
- 函数逻辑简单,没有循环和递归
不适合内联的场景:
- 函数体很大,内联会导致代码膨胀
- 函数有复杂逻辑,编译器可能拒绝内联
- 虚函数通常不能内联(除非编译器能确定实际类型)
嵌入式开发中,代码空间有限,要谨慎使用inline,避免代码膨胀。
4.vector容器的扩容机制是什么?
vector是动态数组,当元素数量超过容量时,会自动扩容。扩容机制是:
分配新内存:通常是当前容量的1.5倍或2倍(不同编译器实现不同,GCC是2倍,MSVC是1.5倍)。
拷贝元素:将旧内存中的元素拷贝或移动到新内存。如果元素有移动构造函数,使用移动;否则使用拷贝。
释放旧内存:释放旧的内存空间。
vector<int> vec; cout << "capacity: " << vec.capacity() << endl; // 0 vec.push_back(1); cout << "capacity: " << vec.capacity() << endl; // 1 vec.push_back(2); cout << "capacity: " << vec.capacity() << endl; // 2 vec.push_back(3); cout << "capacity: " << vec.capacity() << endl; // 4(扩容为2倍) vec.push_back(4); vec.push_back(5); cout << "capacity: " << vec.capacity() << endl; // 8(再次扩容)
扩容的性能影响:
- 扩容需要分配内存、拷贝元素、释放内存,开销较大
- 如果频繁扩容,性能会下降
- 可以用reserve()预分配空间,避免频繁扩容
vector<int> vec;
vec.reserve(1000); // 预分配1000个元素的空间
for (int i = 0; i < 1000; i++) {
vec.push_back(i); // 不会触发扩容
}
capacity和size的区别:
- size是当前元素个数
- capacity是已分配的空间大小
- capacity >= size
嵌入式开发中,内存有限,要注意vector的内存占用。如果知道元素数量,最好用reserve预分配,避免扩容带来的内存碎片和性能损失。
5.STL中哪些容器是定长的,哪些是变长的?
变长容器(动态大小):
- vector:动态数组,可以自动扩容
- deque:双端队列,可以在两端高效插入删除
- list:双向链表,可以在任意位置插入删除
- map/set:红黑树实现,可以动态增删元素
- unordered_map/unordered_set:哈希表实现,可以动态增删元素
- string:本质是vector,可以动态增长
定长容器(固定大小):
- array(C++11):固定大小的数组,大小在编译期确定
std::array<int, 10> arr; // 固定10个元素,不能改变大小
半定长容器:
- stack、queue、priority_queue:适配器,底层可以用vector或deque,大小可变但不直接控制
区别:
- 变长容器可以动态增删元素,灵活但有内存管理开销
- 定长容器大小固定,性能好但不灵活
- 嵌入式开发中,如果元素数量确定,优先用array,避免动态内存分配
// 嵌入式中推荐的用法 std::array<int, 100> buffer; // 栈上分配,不需要动态内存 // 如果必须用变长容器,预分配空间 std::vector<int> vec; vec.reserve(100); // 避免频繁扩容
6.static关键字有哪些作用?
static在不同上下文中有不同的作用。
修饰局部变量:变量的生命周期延长到程序结束,但作用域仍是局部的。只初始化一次,保持上次的值。
void func() {
static int count = 0; // 只初始化一次
count++;
cout << count << endl;
}
func(); // 输出1
func(); // 输出2
func(); // 输出3
修饰全局变量或函数:限制作用域在当前文件,其他文件不可见。用于避免命名冲突。
// file1.cpp
static int global_var = 10; // 只在file1.cpp中可见
static void helper() { // 只在file1.cpp中可见
// ...
}
修饰类成员变量:所有对象共享同一个变量,属于类而不是对象。必须在类外初始化。
class MyClass {
public:
static int count; // 声明
};
int MyClass::count = 0; // 定义和初始化
MyClass obj1, obj2;
obj1.count = 10;
cout << obj2.count; // 输出10,共享同一个变量
修饰类成员函数:不依赖于对象,可以通过类名直接调用。不能访问非静态成员。
class MyClass {
public:
static void func() {
// 只能访问静态成员
}
};
MyClass::func(); // 通过类名调用
嵌入式开发中的应用:
- 用static局部变量保存状态,避免全局变量污染
- 用static限制函数和变量的作用域,避免命名冲突
- 用static成员实现单例模式
7.sizeof的作用是什么?sizeof一个指针结果是多少?
sizeof是编译期运算符,用于计算类型或变量的字节大小。
基本类型的大小:
sizeof(char);
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
这是一个全面的嵌入式面试专栏。主要内容将包括:操作系统(进程管理、内存管理、文件系统等)、嵌入式系统(启动流程、驱动开发、中断管理等)、网络通信(TCP/IP协议栈、Socket编程等)、开发工具(交叉编译、调试工具等)以及实际项目经验分享。专栏将采用理论结合实践的方式,每个知识点都会附带相关的面试真题和答案解析。
