其实,嵌入式岗位近几年还是非常火的,好多小伙伴都会选择这个方向,而且,薪资方面也是挺香的。所以,对于不想卷后端的小伙伴们,嵌入式也是一种不错的选择。
那么,这个岗位对应届生的要求高吗?相对来说,比后端Java、C++好点,对于语言要求,嵌入式也是需要熟练C语言的,所以就会有C/C++选手钟意嵌入式。
今天带大家学习这位小伙伴的360嵌入式面经。
面经问题来源:https://www.nowcoder.com/feed/main/detail/22a2f509f0a94c3cbb8ba485de084d19
1.Wi-Fi关联是怎么做的了解过吗(看我有过Wi-Fi路由器开发的项目)
Wi-Fi关联是指无线设备(如手机、电脑)与Wi-Fi接入点之间建立连接的过程。了解一些基本概念可以帮助理解关联的过程:
- SSID(Service Set Identifier):也称为Wi-Fi网络名称,是一个用于标识无线网络的字符串。
- BSSID(Basic Service Set Identifier):唯一标识一个Wi-Fi接入点的物理地址。
- 信道(Channel):Wi-Fi使用不同的频段和信道进行通信。
当设备要连接到某个Wi-Fi网络时,它会执行以下步骤:
- 扫描:设备会扫描附近可用的Wi-Fi网络,并获取它们的SSID、BSSID和信号强度等信息。
- 选择网络:根据一定算法,设备选择要连接的目标网络。
- 关联请求:设备向选定的目标网络发送关联请求。该请求包含设备自身的MAC地址、认证信息等。
- 认证与加密:接入点收到关联请求后,根据预先设置好的安全机制(如WPA2密码),进行认证和加密过程以验证设备身份。
- 分配IP地址:认证成功后,接入点将为设备分配一个IP地址,使其能够在局域网中进行通信。
- 关联确认:接入点向设备发送关联确认消息,表示连接已建立。
通过这些步骤,设备与Wi-Fi接入点成功关联,可以开始进行数据传输。整个过程的具体细节和实现方式可能会因不同的Wi-Fi标准(如802.11n、802.11ac)和设备操作系统而有所差异。
2. TCP保证可靠性有哪些措施
TCP(传输控制协议)通过以下几种措施来保证可靠性:
- 序列号和确认应答:每个TCP报文段都会分配一个唯一的序列号,接收端通过发送确认应答来告知发送端已成功接收到数据。
- 超时重传:发送端在发送数据后会启动一个定时器,如果在规定时间内没有收到确认应答,就会重新发送该数据段。
- 滑动窗口:TCP使用滑动窗口机制来实现流量控制和拥塞控制。接收端通过通告窗口大小来告诉发送端可以接收的数据量,从而避免过多的数据堆积。
- 丢包重传:如果发生丢包,接收方可以通过请求重传丢失的数据段来实现可靠性。
- 流量控制:TCP使用滑动窗口机制来进行流量控制,根据接收方的处理能力和网络状况调整发送速率,避免过载造成数据丢失或延迟。
- 拥塞控制:TCP通过拥塞窗口、慢启动、拥塞避免等算法来感知并控制网络拥塞情况,以避免过度拥塞导致网络性能下降。
这些机制共同确保了TCP的可靠性,使得数据在传输过程中可以准确无误地被接收方接收到。
4. 如何用C语言实现大小端
在C语言中,可以使用联合体(union)来实现大小端的转换。
首先,定义一个32位无符号整型数(例如uint32_t),然后定义一个联合体,该联合体包含一个该类型的成员和一个4字节大小的字符数组。如下所示:
#include
#include
typedef union {
uint32_t value;
unsigned char bytes[4];
} EndianConverter;
接下来,我们可以编写函数来判断当前系统是大端还是小端。在小端系统中,最低有效字节存储在最低地址上;而在大端系统中,最高有效字节存储在最低地址上。
int isLittleEndian() {
EndianConverter converter;
converter.value = 1;
return converter.bytes[0] == 1; // 如果第一个字节为1,则为小端
}
你也可以编写函数来进行大小端转换:
uint32_t swapEndian(uint32_t value) {
EndianConverter converter;
converter.value = value;
unsigned char temp = converter.bytes[0];
converter.bytes[0] = converter.bytes[3];
converter.bytes[3] = temp;
temp = converter.bytes[1];
converter.bytes[1] = converter.bytes[2];
converter.bytes[2] = temp;
return converter.value;
}
这样就可以通过调用 isLittleEndian() 函数来判断系统是否为小端,并且通过调用 swapEndian() 函数来实现大小端之间的转换。
5. 802.11ax和802.11ac/n这些有什么区别
02.11ax(Wi-Fi 6)和802.11ac/n(Wi-Fi 5)都是无线局域网(WLAN)的标准。它们之间有以下区别:
- 性能:802.11ax提供更高的数据传输速度和更大的容量,比802.11ac/n更快。它支持更多同时连接设备,并且可以在拥挤的网络环境中提供更稳定的性能。
- 频段利用率:802.11ax引入了一些新技术,如OFDMA(正交频分多址)和MU-MIMO(多用户多输入多输出),可以将信道划分为较小的子信道并同时传输给多个设备,以提高频段利用率。
- 网络效率:802.11ax使用了一些优化算法,如目标唤醒时间(TWT)和空闲状态电源管理,以降低功耗并延长设备电池寿命。
- 向后兼容性:虽然两者不直接兼容,但大部分现有设备仍可通过向下兼容模式与802.11ax或802.11ac/n网络通信。
6. 进程和线程的区别
进程和线程是操作系统中两个重要的概念,它们都是并发执行任务的方式,但有一些关键的区别:
- 调度:进程是操作系统分配资源和调度的基本单位,每个进程都有独立的地址空间、内存和其他系统资源。而线程是在进程内部创建和调度的,多个线程共享同一个进程的资源。
- 资源开销:由于每个进程都具有独立的资源,因此创建和销毁进程时会产生较大的开销。而线程相对较轻量级,在同一个进程中创建和切换线程时开销较小。
- 通信与同步:不同进程之间通信比较复杂,需要使用特定机制(如管道、消息队列等)。而在同一个进程内部,线程可以直接通过共享内存进行通信,并且可以使用锁等机制实现线程间的同步。
- 容错性:由于每个进程有独立的地址空间,所以一个进程崩溃不会影响其他进程。但在多线程情况下,一个线程崩溃可能会导致整个进程崩溃。
7. 多进程编程实现
在多进程编程中,可以使用以下方法来实现:
- 使用操作系统提供的多进程API,例如fork()函数。通过调用fork()函数,父进程创建一个子进程,子进程会完全复制父进程的代码和数据,并从fork()函数处开始执行。这样就可以实现多个并行运行的进程。
- 使用Python中的multiprocessing模块。该模块提供了方便的接口来创建和管理多个子进程。你可以使用Process类来创建新的进程对象,并使用start()方法启动它们。
- 使用线程池或进程池。线程池或进程池是一种管理并发任务的方式,通过预先创建一定数量的线程或进程,在需要时将任务分配给它们执行。这种方式可以避免频繁地创建和销毁线程或进程带来的开销。
- 利用消息队列进行通信。不同的进程之间可以通过共享消息队列来进行通信和协调工作。一个进程可以将消息发送到队列中,其他相关进程则可以从队列中读取并处理这些消息。
8. MCS是什么(没料到嵌入式还问物理层)
MCS通常是指"Minecraft Coder Pack",是一个用于修改游戏《Minecraft》的工具包。它允许开发者对游戏进行自定义修改和编程。通过使用MCS,开发者可以创建新的游戏内容、添加新的功能和改变游戏的行为。这个工具包提供了一系列API和库,方便开发者进行修改和扩展。
9. C语言中如何防止同一个.h文件被重复 #include
在C语言中,可以使用预处理指令 #ifndef、#define 和 #endif 来防止同一个头文件被重复包含。具体步骤如下:
1.在头文件的开头加入以下代码:
#ifndef HEADER_FILE_NAME_H
#define HEADER_FILE_NAME_H
// 头文件的内容
#endif
2.替换其中的 HEADER_FILE_NAME_H 为你自定义的宏名,一般以头文件名全大写并添加后缀 _H。
3.这样,在每次包含该头文件之前,预处理器会先检查是否已经定义了该宏。如果没有定义,则继续执行 #define 和后续代码;如果已经定义了该宏,则跳过整个头文件的内容。
通过这种方式,可以确保同一个头文件在同一个源代码中只被包含一次,避免了重复声明和定义导致的编译错误。
10. 动态链接和静态链接分别是什么
动态链接和静态链接是软件开发中常用的两种链接方式。
静态链接是将程序所需的所有库文件在编译时直接嵌入到可执行文件中。这意味着生成的可执行文件独立于外部库,可以单独运行。静态链接的优点是简单、方便,不需要额外的依赖,但缺点是可执行文件较大。
动态链接是在程序运行时,由操作系统加载所需的共享库并进行链接。相比于静态链接,动态链接生成的可执行文件较小,并且多个程序可以共享同一个动态库实例,减少内存占用。此外,如果共享库更新了,只需要替换对应的库文件即可。
11. 对指针的理解
指针是C++中的一种数据类型,它存储了一个变量的内存地址。通过指针,可以直接访问或修改该内存地址上的数据。
在C++中,通过使用取地址运算符"&"可以获取变量的内存地址,并将其赋给相应的指针变量。例如:
int num = 10;
int* ptr = # // 将num的地址赋给ptr
可以使用解引用运算符"*"来访问指针所指向的值。例如:
cout << *ptr; // 输出ptr所指向的值(即num的值)
还可以进行指针间的操作,如指针之间的赋值、比较等。
需要注意的是,在使用指针时要确保指针有效且不为空,避免空指针异常和未定义行为。
指针在C++中广泛用于动态内存分配、数组操作、函数传递参数等场景,是C++中重要且强大的特性之一。
12. 函数指针怎么使用 有什么作用
函数指针是指向函数的指针变量。它可以用来存储函数的地址,使得我们可以通过函数指针来调用对应的函数。
要声明一个函数指针,可以使用以下语法:
返回类型 (*指针变量名)(参数列表);
例如,假设有一个名为 add 的函数,它接受两个整数参数并返回它们的和。我们可以声明一个与该函数匹配的函数指针如下:
int (*ptr)(int, int);
然后,我们可以将 add 函数的地址赋给这个函数指针:
ptr = &add;
或者简写为:
ptr = add;
现在,我们就可以通过函数指针来调用 add 函数了:
int result = ptr(3, 4); // 调用 add 函数
使用函数指针的好处之一是它允许动态地选择和调用不同的函数。这在编程中很有用,特别是当需要根据运行时条件决定执行哪个具体的函数时。
此外,函数指针也常用于作为回调机制,在某些情况下允许将一个函数传递给另一个函数作为参数,并在需要时进行调用。
13. TCP/IP网络模型一共几层 哪几层
TCP/IP网络模型一共有四层,它们是:
- 网络接口层(Network Interface Layer):负责处理与物理网络介质的通信,如以太网、Wi-Fi等。
- 网际层(Internet Layer):提供了数据在不同网络之间的路由和转发功能,使用IP协议进行寻址和传输。
- 传输层(Transport Layer):提供端到端的数据传输服务,常用的协议有TCP (Transmission Control Protocol) 和UDP (User Datagram Protocol)。
- 应用层(Application Layer):提供各种应用程序与网络通信的接口,包括HTTP、FTP、SMTP等协议。
这些层级组成了TCP/IP网络模型,用于实现互联网中不同设备之间的通信。
14. ARP协议具体干什么的
ARP(Address Resolution Protocol,地址解析协议)是一种用于将IP地址转换为物理MAC地址的协议。在网络通信中,数据包需要知道目标主机的MAC地址才能正确传递。而ARP协议就是用来通过发送广播请求获取一个目标IP对应的MAC地址。
具体来说,当一个主机需要与另一个主机进行通信时,它会首先检查自己的本地ARP缓存表,看是否已经有了目标IP对应的MAC地址记录。如果没有,则会发送一个ARP请求广播到局域网上的所有主机,询问哪个主机拥有该IP地址对应的MAC地址。收到这个请求的主机会检查自己的IP地址,并向发出请求的主机发送一个ARP响应包含其自己的MAC地址。
一旦发起方收到了目标主机返回的ARP响应包含目标主机的MAC地址后,它就可以使用这个MAC地址将数据包直接发送给目标主机,从而建立起有效通信。
精品文章推荐阅读: