嵌入式软件开发 网上搜集的题目
1.Static关键词的作用?
static
关键字有三个主要作用:
- 局部变量:在函数内部,
static
局部变量只初始化一次,且在函数调用结束后仍然保留其值。 - 全局变量/函数:在文件内部,
static
限制全局变量或函数的作用域,使其仅对当前文件可见。 - 类成员:在类中,
static
成员变量或函数属于类本身而非某个对象,可以不通过对象访问。
好的,我将通过三个简短的代码示例来解释 static
关键字的三个主要作用:
1. 局部变量的 static
作用
在函数内部,static
局部变量的值在多次调用中保持不变,并且只初始化一次。
#include <iostream>
void counter() {
static int count = 0; // 只初始化一次
count++;
std::cout << "Count: " << count << std::endl;
}
int main() {
counter(); // 输出 Count: 1
counter(); // 输出 Count: 2
counter(); // 输出 Count: 3
}
解释:count
是静态局部变量,函数多次调用时,它的值得以保留并累加。
2. 全局变量/函数的 static
作用
使用 static
限制全局变量或函数的作用域,使其只能在定义它的源文件中可见。
// file1.cpp
static int hiddenVar = 10; // 只能在 file1.cpp 中访问
static void hiddenFunc() {
std::cout << "This is a static function in file1.cpp" << std::endl;
}
// file2.cpp
// hiddenVar 和 hiddenFunc 在此不可访问
解释:hiddenVar
和 hiddenFunc
只能在 file1.cpp
中使用,file2.cpp
无法访问它们。
3. 类成员的 static
作用
static
类成员属于类本身,而不是某个对象,且所有对象共享这一成员。
#include <iostream>
class MyClass {
public:
static int sharedValue; // 静态成员变量
static void display() { // 静态成员函数
std::cout << "Shared value: " << sharedValue << std::endl;
}
};
int MyClass::sharedValue = 42;
int main() {
MyClass::display(); // 通过类名访问静态成员函数
MyClass obj1, obj2;
obj1.sharedValue = 100;
MyClass::display(); // 输出 Shared value: 100(所有对象共享该值)
}
解释:sharedValue
是类的静态成员,所有 MyClass
对象共享这一个变量。
4.指针常量和常量指针
-
常量指针(Pointer to Constant):指向的值是常量,不能修改这个值,但指针可以指向其他地址。
- 作用:用来保护指向的数据不被修改。
const int* ptr;
-
指针常量(Constant Pointer):指针本身是常量,不能改变指向的地址,但可以修改指向的值。
- 作用:用来确保指针始终指向同一地址。
int* const ptr;
typedef和define有什么区别?
typedef
用于定义类型别名,遵循编译器检查;#define
是预处理宏替换,直接文本替换,无类型检查。
4.野指针是什么
没有初始化的指针,他被随机指向内存中的一块位置
5. C语言中内存分配的方式有几种?
(a)静态存储区分配
内存分配在程序编译之前完成,且在程序的整个运行期间都存在,例如全局变量、静态变量等
(b)栈上分配
在函数执行时,函数内的局部变量的存储单元在栈上创建,函数执行结束时这些存储单元自动释放局部变量、函数内参数都在栈上
(c) 堆上分配
New开辟的空间在堆上
6.说一说指针的理解,二级指针,三级指针等,对函数指针的理解等。
由于c中存在着内存管理的概念,所以指针应运而生,指针是存储内存地址的变量,二级、三级指针分别存储指针的地址,函数指针存储函数的地址并可用于调用函数。
7.简单说说extern、static、const、voliate的作用
extern
用于声明外部变量或函数,static
用于定义静态变量,比如函数内的局部静态变量,以及限制作用域的全局静态变量,防止其他文件读取,const
定义不可修改的常量,可以用于定义常量、定义常量指针、常量形参等,volatile
避免编译器优化,直接从内存地址读数据而不是寄存器。
8.简单说说指针的运用场景。
1.动态内存管理
2.函数参数传递
3.数组和字符串操作
4.一些数据结构会用到如链表
9.C++11的语法
10.Linux常用指令
常用Linux指令有:
ls
列出目录内容cd
切换目录pwd
显示当前路径cp
复制文件/目录mv
移动或重命名文件/目录rm
删除文件/目录cat
查看文件内容grep
搜索文本chmod
修改权限ps
查看进程top
实时监控系统资源df
查看磁盘使用情况du
查看文件/目录大小ssh
远程登录tar
打包或解包文件
11.简单说说SQL优化和索引结构
SQL优化主要通过减少查询时间和资源消耗实现,常见方法包括:合理使用索引、避免全表扫描、减少子查询、使用连接代替嵌套查询等。
索引结构常见的有两种:
- B+树索引:用于快速查找范围查询、排序,适合大部分场景。
- 哈希索引:用于精确匹配查询,但不支持范围查询。
索引能加快查询速度,但要避免过多索引影响写操作性能。
12. 简单说说多线程
C++多线程通过标准库中的<thread>
实现,允许并发执行多个线程。常用功能包括:
std::thread
:创建和管理线程。- 同步机制:使用
mutex
、lock
、condition_variable
等避免数据竞争和死锁,确保线程安全。 join
与detach
:join
让主线程等待子线程完成,detach
使线程独立执行。- 线程池:可以通过
async
或第三方库创建线程池,提升并发效率。
多线程用于加速计算、处理I/O密集型任务、或实现并行数据处理。
13. 简单说说重写和重载
重写(Override)是子类重新定义父类的虚函数,保持函数签名一致,实现多态。
重载(Overload)是同一作用域内定义多个同名函数,通过不同参数类型或数量区分调用。
14.说说C++中的虚函数和纯虚函数
虚函数是通过virtual
关键字声明的函数,允许子类重写以实现运行时多态。调用时根据对象的实际类型选择合适的函数版本。
纯虚函数(= 0
)是没有实现的虚函数,要求子类必须重写,声明类为抽象类,不能直接实例化。
15. 一个程序从开始运行到结束的完整过程(四个过程)
预处理(Pre-Processing)、编译(Compiling)、汇编(Assembling)、链接(Linking)
16. 计算机中,32bit与64bit有什么区别
64bit计算主要有两大优点:可以进行更大范围的整数运算;可以支持更大的内存寻址。
17. Linux 操作系统关机、重启相关命令
关机:shutdown now 或 poweroff
重启:reboot 或 shutdown -r now
取消关机:shutdown -c
1、改变文件属性的命令:chmod (chmod 777 /etc/squid 运行命令后,squid文件夹(目录)的权限就被修改为777(可读可写可执行))
2、查找文件中匹配字符串的命令:grep
3、查找当前目录:pwd
4、删除目录:rm -rf 目录名
5、删除文件:rm 文件名
6、创建目录(文件夹):mkdir
7、创建文件:touch
8、vi和vim 文件名也可以创建
9、解压:tar -xzvf 压缩包
打包:tar -cvzf 目录(文件夹)
18.说一个linux下编译优化选项:
加:-o
10.12日 笔面记录 嵌入式软件开发
笔试很简单
-
考察static的几个用法 给了一段代码 里面有函数内static 全局static 函数static
-
分别在堆、栈以及全局静态空间上申请100个int大小的空间的C语句
栈 即局部变量 int arr_stack[100]; // 在栈上分配100个int大小的空间 堆 即动态分配内存 需要手动释放内存的 int *arr_heap = (int *)malloc(100 * sizeof(int)); // 在堆上分配100个int大小的空间 全局静态空间 static int arr_global[100]; // 在全局静态空间分配100个int大小的空间 或者在全局作用域部分定义
-
写宏 求数组中元素个数
#define Length(table) (sizeof(table) / sizeof(table[0])) -
程序改错
malloc分配时应该是length+1
指针指向数组末尾元素也应该是len-1
复制字符串应该是*d++=s–
*d没有加终止符
malloc的内存没有free -
字符串转整数
-
计算因子之和
面试
1.你在用Linux的时候常用哪些指令?
-
文件和目录操作:
ls
:列出目录内容cd
:切换目录cp
:复制文件或目录mv
:移动或重命名文件rm
:删除文件或目录mkdir
:创建目录touch
:创建空文件或更新文件时间戳
-
文件内容查看:
cat
:显示文件内容more
、less
:分页查看文件内容head
、tail
:查看文件的前几行或后几行grep
:查找文件中的特定字符串find
:查找文件
-
系统管理:
ps
、top
:查看进程信息kill
:结束进程df
、du
:查看磁盘使用情况free
:查看内存使用情况
-
网络配置:
ifconfig
、ip
:查看和配置网络接口ping
:测试网络连通性netstat
:查看网络连接scp
、rsync
:远程文件传输
增、删、改、查对应的指令
-
增(创建)
touch filename
:创建一个空文件mkdir dirname
:创建一个目录echo "text" > filename
:创建一个文件并写入内容cp source destination
:复制文件或目录
-
删(删除)
rm filename
:删除文件rm -r dirname
:删除目录及其内容rmdir dirname
:删除空目录
-
改(修改)
nano filename
、vi filename
、vim filename
:编辑文件内容mv oldname newname
:重命名文件或目录chmod
、chown
:修改文件权限或所有者
-
查(查看)
cat filename
:查看文件内容less filename
:分页查看文件内容grep "pattern" filename
:查找文件中的特定内容find /path -name "filename"
:在指定路径下查找文件
2.epoll了解的多么 你常用到么.
epoll
是 Linux 特有的一种 I/O 多路复用机制,相比于传统的 select
和 poll
,它在性能和可扩展性上有很大优势。主要优点包括:
- 性能更高:
epoll
在处理大量文件描述符时效率更高,因为它不需要像select
一样线性扫描整个文件描述符集合。 - 支持边缘触发(Edge Triggered, ET)和水平触发(Level Triggered, LT),这使得它可以灵活应对不同的 I/O 事件。
- 减少了不必要的系统调用:当有新的 I/O 事件到来时,
epoll
会通知程序,而不像select
或poll
每次都要重新遍历整个文件描述符集合。
2. epoll
的常见使用场景:
- 高并发网络编程:比如设计 HTTP 服务器或者 WebSocket 服务,在处理数千甚至数万的连接时,
epoll
能够高效地监控多个 socket 事件。 - 嵌入式系统的异步 I/O:如果需要同时监控多个传感器、外设或其他 I/O 设备的输入/输出,
epoll
是一个非常好的选择,能够有效地提升系统的响应速度。
3. epoll
的常用函数:
使用 epoll
时,通常会用到以下几个系统调用:
epoll_create
:创建一个epoll
实例,返回一个文件描述符,用于后续的操作。epoll_ctl
:向epoll
实例中添加、修改或删除监听的文件描述符。EPOLL_CTL_ADD
:添加新的文件描述符EPOLL_CTL_MOD
:修改已有文件描述符的监听事件EPOLL_CTL_DEL
:从epoll
实例中移除文件描述符
epoll_wait
:阻塞等待直到一个或多个事件发生,然后将事件返回给用户空间。
3.Socket了解的多么 你怎么理解的?
Socket 是网络编程中最基础的通信机制,它是进程间通信的一种手段,允许两个设备通过网络相互传输数据。在嵌入式系统中,Socket 通常用于设备与服务器之间的通信、远程控制、数据传输等。
服务器端 Socket 流程:
- 创建 Socket:使用
socket()
函数创建一个 Socket,指定协议族(如AF_INET
用于 IPv4)、传输类型(如SOCK_STREAM
用于 TCP)。 - 绑定地址和端口:使用
bind()
函数将创建的 Socket 绑定到本地 IP 地址和端口。 - 监听连接:使用
listen()
函数使 Socket 进入监听模式,等待客户端连接。 - 接受连接:使用
accept()
函数接收客户端的连接请求,返回一个新的 Socket 描述符用于与该客户端进行通信。 - 发送和接收数据:使用
send()
和recv()
函数进行数据传输。 - 关闭 Socket:当通信结束时,使用
close()
函数关闭 Socket。
客户端 Socket 流程:
- 创建 Socket:同样使用
socket()
函数创建一个 Socket。 - 连接服务器:使用
connect()
函数向服务器发起连接请求,连接成功后可以进行数据传输。 - 发送和接收数据:使用
send()
和recv()
函数与服务器进行通信。 - 关闭 Socket:完成数据传输后关闭 Socket。
5. 嵌入式系统中的 Socket 应用
在嵌入式系统中,Socket 被广泛用于以下场景:
- 远程设备管理:通过 TCP/IP 通信,服务器可以远程控制嵌入式设备,收集数据或下发指令。
- 物联网 (IoT) 通信:嵌入式设备作为物联网节点,通过 Socket 进行云端数据上传和下发。
- 实时数据传输:比如,嵌入式传感器数据通过 Socket 传输到中央服务器或处理系统进行进一步的处理和存储。
4.生产者消费者模型是什么 如何用其优化代码?
生产者-消费者模型(Producer-Consumer Model)是一个经典的多线程同步问题,用于解决多线程程序中不同任务之间的协调问题。它广泛应用于缓冲区、队列、流处理等场景,用来协调数据的生成和数据的使用。
1. 基本概念:
生产者-消费者模型中,有两个主要角色:
- 生产者:负责生成数据(任务、消息、资源等),并将其放入共享的缓冲区或队列中。
- 消费者:负责从共享缓冲区中取出数据并进行处理。
这两者通过一个**共享缓冲区(队列)**进行通信。生产者生成的数据存入缓冲区,而消费者从缓冲区中取出数据进行处理。问题在于如何确保两者在高效并发的情况下不会导致资源竞争或缓冲区溢出/空转。
2. 问题的核心挑战:
- 互斥:生产者和消费者不能同时访问缓冲区,防止多个线程对共享资源进行并发访问导致数据不一致。
- 同步:当缓冲区满时,生产者需要等待消费者取走数据;当缓冲区空时,消费者需要等待生产者生成数据。
5.进程间如何通信?
管道 消息队列 共享内存 信号量 套接字 信号
之间的差异
6.多线程要注意什么?
多线程编程需要注意以下几点:
-
线程安全:多个线程访问共享资源时,必须使用同步机制(如锁、互斥量)防止数据竞争和数据不一致。
-
死锁:避免多个线程相互等待资源造成的死锁。使用顺序加锁、尝试加锁或超时机制来预防。
-
上下文切换:频繁切换会带来性能开销,尽量减少不必要的线程切换。
-
资源泄漏:确保每个线程正确释放资源(如内存、文件句柄)。
7.常用的数据结构有哪些?链表有哪几种?
数组 链表 栈 队列 哈希表 树 堆 图
单链表 双向链表 循环链表 双向循环链表