嵌入式linux八股文

article/2025/6/7 23:47:02

1.指针的大小

指针大小的计算方式。指针的大小并非由其类型决定,而是与编译器的位数相关。具体来说,在 32 位的系统下,指针的大小为 4 个字节,而在 64 位的系统下,指针的大小为 8 个字节。通过示例代码的运行,验证了这一结论。

2.函数指针和指针函数的区别

函数指针是指向函数的指针,可以通过定义一个函数指针来指向一个函数。而定义函数指针的方法是将函数的返回值、类型和名字复制过来,修改名字并加上指针符号。

指针函数则是指函数的返回值是一个指针的函数,可以通过函数的返回值来判断是否为指针函数。

3.sizeof和strlen的区别

首先,它们一个是运算符,一个是函数,使用时需要包含相应的头文件。其次,size of 计算的是内存大小,而 string len 计算的是字符串长度,且不包括结尾的 '\0'。此外,size of 还可以计算其他类型的大小,如 int 和 float。

4.数组指针和指针数组的区别

数组指针:

#include <stdio.h>
#include <stdlib.h>int main(void) {int (*p)[10];  // 数组指针int arr[10] = {1,2,3,4,5,6,7,8,9,10};  // 整型数组p = &arr;  // 正确:p指向一个包含10个整数的数组return 0;
}

指针数组:

#include <stdio.h>
#include <stdlib.h>int main(void) {int *a, *a1, *a2;// 初始化指针a = (int*)malloc(sizeof(int));a1 = (int*)malloc(sizeof(int));a2 = (int*)malloc(sizeof(int));if (a == NULL || a1 == NULL || a2 == NULL) {printf("内存分配失败!\n");return 1; // 退出程序}*a = 10;   // 赋值*a1 = 20;*a2 = 30;int* p1[10] = {a, a1, a2, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; // 指针数组printf("a 的值为: %d\n", *p1[0]);printf("a1 的值为: %d\n", *p1[1]);printf("a2 的值为: %d\n", *p1[2]);free(a);  // 释放内存free(a1);free(a2);return 0;
}

5.C 语言中内存分配的方式

  1. 静态存储区分配:

    • 在程序编译时就已经分配好,在程序的整个运行期间都存在。
    • 全局变量和 static 变量(包括全局 static 变量和局部 static 变量)是存储在此区域的。
    • 程序结束后由系统自动释放。
  2. 栈上分配:

    • 在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。
    • 栈内存分配运算内置于处理器的指令集中,效率很高,但分配的内存容量有限。
    • 使用栈分配不需要手动释放内存。
  3. 堆上分配(动态内存分配):

    • 程序运行时使用 malloccallocrealloc 等函数动态地分配内存,用 free 函数释放。
    • 堆内存允许程序在运行时根据需要动态地申请和释放内存,灵活性高。
    • 程序员负责内存的申请和释放,如果分配后不释放,可能会导致内存泄漏。

6.结构体和联合体的区别

联合体的成员共享一块内存地址,大小等于成员中占内存最大的那个成员的大小。而结构体的不同成员放在不同的地址中,大小等于所有成员大小之和,需要注意字节对齐。联合体的成员更改一个值会影响其他成员,结构体则不会。

7.野指针的概念及其原因

野指针是指向不可用内存的指针,常见原因包括指针创建时未赋值、指针被释放后未重新赋值以及指针越界。避免野指针的方法包括初始化时赋值、释放后重新赋值以及避免数组越界。

8.数组和链表的区别

首先,数组的地址空间是连续的,而链表的地址空间是不连续的。其次,数组可以通过下标直接访问元素,访问速度比链表快。最后,链表在插入和删除操作(已知位置时)不需要移动大量元素,操作更为方便,时间复杂度通常优于数组;但链表查找元素需逐个遍历节点,查找速度一般不如数组。

9.编写一个宏返回输入参数中较小的一个

#include <stdio.h>#define Min(a,b) ((a)<(b)?(a):(b))int main(){printf("Min: %d",Min(5,4));return 0;
}

注意a和b加括号

10.全局变量和局部变量的区别

首先,从作用域来看,全局变量的作用域为程序块,而局部变量的作用域为当前函数内部。

其次,从生命周期来看,全局变量的生命周期是整个程序,而局部变量的生命周期是当前的函数。

再者,从存储方式来看,局部变量存储在栈中,而全局变量存储在全局数据区中。

最后,从使用方式来看,全局变量可以在程序的各个部分使用,而局部变量只能在函数的内部使用。

11.define和typedef的区别

预处理指令与关键字
define 是 C/C++ 中的预处理指令,在编译前进行文本替换,不进行语法检查。typedef 是关键字,在编译阶段处理,会对类型合法性进行检查。

作用域限制
define 没有作用域限制,从定义处到文件末尾或取消定义处均有效。typedef 遵循作用域规则,如在函数内定义则仅在该函数内有效。

指针处理

define 对指针的操作可能产生歧义,例如:

#define PINT int*
PINT a, b;  // 实际为 int* a, int b(b不是指针)

typedef 能正确重命名指针类型:

typedef int* PINT;
PINT a, b;  // a 和 b 均为 int* 类型

类型安全
typedef 会检查类型是否存在,避免错误。define 直接替换文本,可能因拼写错误导致未定义行为。

调试支持
typedef 定义的类型在调试器中可见,define 的宏替换在调试阶段已消失,不利于排查问题。

12.static的作用

首先,static用于定义静态变量或函数,限制其作用域

其次,如果在函数体内定义static变量,该变量只会被初始化一次。

再次,static变量或函数只能在当前文件中使用,无法被其他文件引用。(生命周期)

最后,函数内部定义的static变量无法被其他函数使用。

13.内存对齐的概念

内存对齐是指在存储数据时,按照一定的规则将数据放置在内存中的过程。

以结构体为例,内存对齐决定了结构体所占用的内存大小。

例如,一个包含 int、short 和 char 的结构体,其内存分配并非简单地将各变量的大小相加,而是遵循内存对齐原则,使得结构体占用的内存大小为最大变量大小的整数倍。

内存对齐有助于提高计算机对内存的访问速度。

14.常量指针和指针常量的区别

  • 指针常量(Constant Pointer):指针本身不可变(如 int* const ptr),但指向的值可变。
  • 常量指针:指向的值不可变,指针可变(const *int ptr)(常量在前,故理解为指向的值为常量)

15.数组名和指针的区别

首先,数组名是数组的首元素的地址,可以看作一个指针常量,不能修改指向。

其次,它们在访问数组的元素时,指针需要解引用,而数组名则是直接访问。

最后,使用 sizeof 对指针和数组名进行计算时,指针的大小与编译器的位数有关,而数组名计算的则是整个数组的大小。

16.堆和栈的区别

内存管理方式:堆是由程序员手动分配和销毁,栈一般系统自动分配和销毁

访问效率:栈的访问速度快,堆较慢

数据结构特性:栈遵循LIFO(后进先出)原则,只有栈顶可操作。堆是完全二叉树结构,支持任意节点的插入和删除。

17.malloc和new区别

返回值:malloc返回void*,new返回对象指针

分配内存:malloc需要指定分配内存的大小,new不需要

定义:malloc是标准库函数,new是c++中的操作符

18.struct和class在C++中的区别

默认访问权限

struct的成员默认是public,而class的成员默认是private。例如:

struct MyStruct {int x; // 默认为public
};class MyClass {int x; // 默认为private
};

默认继承方式

struct的默认继承方式是public,而class的默认继承方式是private。例如:

struct Base {};
struct Derived : Base {}; // 默认为public继承class Base {};
class Derived : Base {}; // 默认为private继承

使用习惯

struct通常用于表示简单的数据聚合(如POD类型),而class常用于封装复杂逻辑和实现面向对象特性(如继承、多态)。例如:

struct Point {int x, y; // 仅作为数据容器
};class Shape {
public:virtual void draw() = 0; // 抽象接口
};

19.C++中的类访问权限

C++ 中的类有三个访问权限:公有的(public)、私有的(private)和受保护的(protected)。

公有的成员可以在类的外部进行访问;

私有的成员只能在类的内部进行访问;

受保护的成员可以在类的内部及子类中进行访问。

20.内联函数的概念、定义及应用

内联函数是一种特殊的函数声明方式,通过在函数前面加上 inline 关键字,指示编译器在调用该函数时将其展开,而不是直接进行调用。内联函数的主要作用是减小函数调用的开销,提高执行效率,并允许编译器进行优化。

21.使用C语言实现strcpy函数        

char *strcpy(char *dest, const char *src) {char *ptr = dest;while (*src != '\0') {*ptr++ = *src++;}*ptr = '\0';return dest;
}

22.程序分为几个段

代码段(Text Segment)

存放可执行指令的只读内存区域。例如:

int main() {return 0;
}

编译后机器指令存储于此段,防止运行时被意外修改。

数据段(Data Segment)

包含已初始化的全局变量和静态变量。例如:

int global_var = 42;  // 存储于数据段

BSS段(Block Started by Symbol)

存储未初始化的全局变量和静态变量,运行时初始化为零。例如:

int uninit_var;  // 存储于BSS段

堆段(Heap Segment)

动态分配的内存区域,通过malloc/new等函数管理。例如:

int *ptr = malloc(sizeof(int));  // 堆内存分配

栈段(Stack Segment)

存放函数调用时的局部变量和返回地址。例如:

void func() {int local_var = 10;  // 存储于栈段
}

23. .c文件转换成可执行文件的过程

首先,进行预处理,展开头文件和宏定义,生成无注释的源代码。

接着进行编译,将预处理后的源代码转换为汇编代码,生成.s 文件。

然后进行汇编,将汇编代码转换为机器码,生成.o 文件。

最后进行链接,将所有.o 文件链接成一个可执行程序。这四个步骤将一个.c文件转化为了可执行程序。

24.静态库和动态库的区别

 静态库(.a)的编译和调用

# 1. 编译 mathlib.c 为目标文件(.o)
gcc -c mathlib.c -o mathlib.o# 2. 打包目标文件为静态库(libmath.a)
ar rcs libmath.a mathlib.o
编译主程序并链接静态库
# 3. 编译 main.c 并链接静态库
gcc main.c -L. -lmath -o main_static

动态库(.so)的编译和调用

# 1. 编译 mathlib.c 为动态库(libmath.so)
gcc -shared -fPIC mathlib.c -o libmath.so
编译主程序并链接动态库
# 2. 编译 main.c 并链接动态库
gcc main.c -L. -lmath -o main_dynamic

运行时的核心区别

虽然编译命令相似,但静态库和动态库在运行时行为完全不同:

特性静态库(.a动态库(.so
代码存储位置库代码直接嵌入可执行文件库代码在外部文件.so)中
运行时依赖无(可执行文件独立运行)必须能找到 .so 文件,否则报错
内存占用每个程序独占库代码副本多个程序共享同一库的内存实例
更新库需重新编译程序替换 .so 文件即可(需保持 ABI 兼容)
加载时机程序启动时全部加载运行时按需加载(可延迟或动态加载)

25.SPI和IIC寻址的区别

特性SPII2C/IIC
寻址方式片选线(CS)设备地址(7位/10位)
设备选择拉低对应片选线发送设备地址
总线复杂度设备多则连线多只需两根线,设备多也简单
适用场景高速、设备少设备多、连线要求简单

26.什么是交叉编译

交叉编译是指在一种计算机架构(称为宿主机或主机)上编译代码,生成可在另一种不同的计算机架构(称为目标机或目标平台)上运行的可执行文件的过程。

27.UART、I²C 和 SPI 这三个通信协议的区别。

首先,UART 使用异步通信,而 I²C 和 SPI 是同步通信,因为它们都有时钟线。

其次,线路数量上,UART 只涉及两根线,SPI 有四根线,I²C 有两根线。

再者,设备数量上,UART 是一对一通信,I²C 支持多主机多从机,SPI 也支持多主机多从机。

此外,传输速率上,I²C 有标准、快速和高速模式,而 SPI 的速度没有具体说明,但通常比 I²C 快。

最后,工作模式上,UART 支持全双工和半双工,I²C 只支持半双工,SPI 支持全双工。

28.SPI有几根线,可以去除哪些线

SPI 总线由四根线组成,分别是 SCLK(时钟线)、MOSI(主设备输出,从设备输入)、MISO(主设备输入,从设备输出)和 CS(片选线)。

其中,SCLK 用于同步数据传输,MOSI 和 MISO 用于数据传输,CS 用于选择设备。

在通信过程中,如果只需要单向传输,可以省略 MISO 或 MOSI 中的一根线;

如果进行一对一通信且不需要选择设备,则可以省略 CS 线。

29.TCP和UDP的区别

首先,TCP 提供可靠的数据传输,通过三次握手确保数据正确到达,而 UDP 则提供不可靠的数据通信。

其次,TCP 是面向连接的通信方式,需要进行连接,而 UDP 则不需要进行连接。

因此,TCP 的通信速率比 UDP 慢。然而,UDP 的速率更快,适合用于视频流、在线游戏和直播等场景。

最后,TCP 适用于邮件和文件传输等需要可靠传输的场景,而 UDP 则适用于对速率要求较高的场景。

30.进程和线程的区别

首先在定义上,进程是资源分配的基本单位,而线程是进程中的执行单元。

其次在资源占用上,进程有自己的独立地址空间,而线程共享进程的地址空间。

接着在容错性上,进程出现问题不会影响其他进程,而线程出现问题可能导致整个程序崩溃。

最后在调度和切换上,进程由调度器进行调度和切换,消耗资源较多,而线程在进程中,消耗资源较少。

31.进程间通信有哪几种方式,哪几种需要借助内核

具体包括管道、命名管道、共享内存、信号量、消息队列、套接字(socket)和信号。

其中,管道、共享内存、信号量、消息队列和套接字需要借助内核实现。

管道和共享内存在内核空间创建共享资源,信号量、消息队列和套接字则完全依赖于内核。

32.什么是DMA

DMA(Direct Memory Access,直接内存访问)是一种计算机系统中常用的硬件技术,允许外设(如硬盘、网卡、声卡、触摸屏控制器等)在不经过CPU干预的情况下,直接与内存进行数据传输

33.进程的状态

状态转换

  1. 就绪态 → 运行态

    • 触发条件:进程被调度器选中,分配CPU资源
    • 例子:时间片轮转调度中,上一个进程的时间片用完,调度器选择就绪队列中的下一个进程
  2. 运行态 → 就绪态

    • 触发条件:进程的时间片用完或优先级更高的进程抢占
    • 例子:一个低优先级进程正在运行,突然有高优先级进程进入就绪态,调度器将CPU分配给高优先级进程

34.僵尸进程、孤儿进程和守护进程的概念与区别。

僵尸进程是指子进程退出后,父进程未调用 wait 或 waitpid 函数获取其退出状态,子进程的信息仍保存在系统中的情况。

孤儿进程是由于父进程异常结束,子进程成为无父进程的状态,会被 init 进程收养。

守护进程则是父进程创建子进程后,故意结束父进程,使得子进程成为守护进程。

35.FreeRTOS 的调度算法

三种调度算法:抢占式调度、时间片轮转和协作式调度。

抢占式调度是指高优先级任务可以打断低优先级任务的执行,适用于优先级不同的任务。

时间片轮转是指相同优先级的任务具有相同大小的时间片,时间片被耗尽时任务会强制退出,适用于相同优先级的任务。

协作式调度则通过  vtaskdelay 函数或其他机制来实现,较少使用。这些调度算法为嵌入式系统提供了灵活的任务管理方式。

36.环形缓冲区的概念及实现

环形缓冲区并非圆形,而是通过数组实现,使用结构体封装。

它包含写指针和读指针,用于记录数据写入和读取的位置。写入时,写指针向后移动,读出时,读指针向后移动。

通过取余操作,实现循环使用。环形缓冲区常用于串口通信,保证数据存储和读取的正确性。

37.构造函数和析构函数的作用与特性

构造函数的作用是初始化对象设定初始值,特性包括名称与类名相同、无返回值、可多重载

析构函数的作用是释放资源,进行清理操作,特性包括无参数无返回值、名称以波浪号开头、不可重载

38.大小端存储

大小端(Endianness)是计算机系统存储多字节数据的两种不同排列方式,主要分为大端序(Big-Endian)和小端序(Little-Endian)。

定义

  • 大端序(Big-Endian):高位字节存储在低地址,低位字节存储在高地址
  • 小端序(Little-Endian):低位字节存储在低地址,高位字节存储在高地址

直观解释

假设有一个32位整数:0x12345678

内存地址
0x10000x10010x10020x1003
大端序0x120x340x560x78
小端序0x780x560x340x12
#include <stdio.h>int main() {unsigned int value = 0x12345678;unsigned char *ptr = (unsigned char *)&value;if (*ptr == 0x78) {printf("系统是小端序\n");} else if (*ptr == 0x12) {printf("系统是大端序\n");} else {printf("未知的字节序\n");}return 0;
}

39.系统调用的概念与重要性

系统调用是用户和内核之间的接口,允许用户空间访问到内核空间。

如果没有系统调用,直接访问内核空间将导致不安全,甚至可能导致内核崩溃。

系统调用流程是用户程序调用 open、read 等函数,这些函数会进入内核空间,调用内核中的相应函数。

40.嵌入式系统中的FIFO

FIFO是一种用于数据缓冲的硬件结构,能够减轻 CPU 负担。它既可以通过软件实现,也可以通过硬件实现。

FIFO的实现方式

1.环形缓冲区(Ring Buffer)
2. 硬件FIFO

许多嵌入式外设如UART、SPI、I2C控制器内部集成了硬件FIFO,通过寄存器进行控制:

// 示例:向UART发送FIFO写入数据
void UART_SendByte(UART_TypeDef *uart, uint8_t data) {// 等待发送FIFO有空间while(!(uart->STATUS & UART_STATUS_TXNFULL)) {}// 写入数据到发送FIFOuart->DATA = data;
}

41.TCP、UDP进行通信的流程

TCP通信步骤

服务端步骤
  1. 创建套接字(socket)
  2. 绑定地址和端口(bind)
  3. 监听连接请求(listen)
  4. 接受客户端连接(accept)
  5. 接收/发送数据(recv/send 或 read/write)
  6. 关闭连接(close)
客户端步骤
  1. 创建套接字(socket)
  2. 连接服务器(connect)
  3. 发送/接收数据(send/recv 或 write/read)
  4. 关闭连接(close)

UDP通信步骤

服务端步骤
  1. 创建套接字(socket,指定SOCK_DGRAM)
  2. 绑定地址和端口(bind)
  3. 接收/发送数据(recvfrom/sendto)
  4. 关闭套接字(close)
客户端步骤
  1. 创建套接字(socket,指定SOCK_DGRAM)
  2. 发送/接收数据(sendto/recvfrom)
  3. 关闭套接字(close)

42.iic的gpio配置为什么要使用开漏输出,并且为什么需要上拉电阻

开漏输出的必要性

1. 多主机总线架构
  • I2C是多主机总线,允许多个设备同时连接到同一条总线上
  • 开漏输出只能输出低电平或高阻态,不能主动输出高电平
  • 这样可以避免多个设备同时驱动总线时发生电流冲突
2. 线与逻辑

// 开漏输出特性

// 当GPIO输出0时:引脚输出低电平

// 当GPIO输出1时:引脚变为高阻态(相当于断开)

  • 只有当所有设备都输出高阻态时,总线才能被上拉电阻拉到高电平
  • 任何一个设备输出低电平,总线就会变为低电平
  • 实现了"线与"逻辑:只有所有设备都"释放"总线,总线才为高

上拉电阻的作用

1. 提供高电平
  • 开漏输出无法主动驱动高电平
  • 上拉电阻将总线拉到VCC,提供逻辑高电平
2. 确保总线空闲状态
  • 当没有设备驱动总线时,上拉电阻确保总线处于高电平(空闲状态)
  • I2C协议规定空闲状态为高电平
3. 支持时钟拉伸
  • 从设备可以通过拉低SCL来延长时钟周期
  • 上拉电阻确保时钟释放后能正确返回高电平

43.取消内存对齐的方式

1.#pragma pack(1)

2.gcc编译器:__attribute__((packed))

44.LINUX 和 RTOS 的区别

首先在应用场景上,LINUX 应用广泛,包括桌面计算机、服务器、嵌入式系统等,而 RTOS 主要应用于小型嵌入式系统。

其次在实时性上,LINUX 不保证实时性,而 RTOS 提供严格的实时性保证。

再者在资源占用上,LINUX 占用资源较多,而 RTOS 占用资源较少。

内存方面,LINUX 有虚拟内存和内核空间、用户空间,而 RTOS 没有。

最后在扩展性上,LINUX 扩展性高,而 RTOS 扩展性有限。

45.软件 I2C 和硬件 I2C 的区别

首先在实现方式上,软件 I2C 通过控制 GPIO 模拟 I2C 的 SCL 和 SDA 信号来产生 I2C 时序,而硬件 I2C 则是 MCU 内部的专用硬件模块,直接通过 I2C 外设生成 I2C 时序。

其次在性能上,软件 I2C 的速度通常较慢,受限于 CPU,而硬件 I2C 可以在高频率下工作,不受 CPU 限制。

最后在可靠性上,硬件 I2C 可靠性较高,而软件 I2C 的可靠性则取决于 CPU 运行速度和程序员的代码设计。

46.多线程 vs 多进程的选择策略

使用多线程的场景

1. I/O密集型任务

// 网络服务器处理多个客户端连接

2. 需要频繁数据共享

// 生产者-消费者模型

3. UI应用程序

// GUI应用:UI线程 + 后台工作线程(Qt)

使用多进程的场景

1. CPU密集型任务

// 并行计算:矩阵乘法

2. 需要高可靠性/容错性

// Web服务器:主进程 + 多个工作进程

3. 独立功能模块

// 系统服务:各模块独立运行

47. Linux 驱动的分类

主要分为三种类型:字符设备驱动、块设备驱动和网络设备驱动。

字符设备驱动适用于处理顺序数据读写,如串口和 LED 灯等;

块设备驱动适用于以块为单位的数据读写,如硬盘和 SSD 等;

网络设备驱动则用于处理网络数据包的发送和接收,如网卡等。

48.什么是中断

*中断(Interrupt)**是CPU在执行程序时,遇到紧急或特殊事件需要立即处理而暂停当前程序执行的机制。

**关中断(Disable Interrupt)**是指暂时禁止CPU响应中断请求的操作,确保某段代码的原子性执行。

49.什么是看门狗

它是一种硬件定时器,用于检测和恢复系统故障。

看门狗定时器要求系统在规定的时间内对它进行复位,这个过程称为喂狗。

如果不进行喂狗操作,计数器会溢出,导致系统重启,防止程序卡死。看门狗定时器可以提高系统的可控性和恢复程序的运行。

50.strcpy和memcpy的区别

特性strcpymemcpy
用途字符串复制任意内存复制
停止条件遇到'\0'复制指定字节数
类型安全仅字符串任意数据类型
性能需要检测'\0'直接复制,更快
安全性容易缓冲区溢出需要正确计算大小
返回值目标字符串指针目标内存指针

51.什么是回调函数

回调函数(Callback Function)是一种编程模式,指作为参数传递给另一个函数的函数,在特定条件满足或事件发生时被调用执行。

基本概念

回调函数的核心思想是:

  • 函数A接收函数B作为参数
  • 在适当的时机,函数A调用函数B
  • 函数B就是回调函数

在C/C++中回调函数通过函数指针实现

52.select,poll和epoll区别

select方式:

fd_set readfds, writefds;FD_ZERO(&readfds);FD_ZERO(&writefds);FD_SET(fd1, &readfds);FD_SET(fd2, &readfds);FD_SET(fd2, &writefds);select(max_fd + 1, &readfds, &writefds, NULL, NULL);if(FD_ISSET(fd1, &readfds)) { /* 处理fd1读 */ }if(FD_ISSET(fd2, &readfds)) { /* 处理fd2读 */ }if(FD_ISSET(fd2, &writefds)) { /* 处理fd2写 */ }

poll方式:

struct pollfd fds[2];
fds[0].fd = fd1; fds[0].events = POLLIN;
fds[1].fd = fd2; fds[1].events = POLLIN | POLLOUT;poll(fds, 2, -1);if(fds[0].revents & POLLIN) { /* 处理fd1读 */ }
if(fds[1].revents & POLLIN) { /* 处理fd2读 */ }
if(fds[1].revents & POLLOUT) { /* 处理fd2写 */ }
特性selectpollepoll
fd数量限制1024无限制无限制
时间复杂度O(n)O(n)O(1)
内存拷贝每次拷贝每次拷贝mmap零拷贝
返回方式遍历所有fd遍历所有fd只返回活跃fd
触发模式水平触发水平触发水平/边缘触发
适用场景少量连接中等连接大量连接
跨平台部分Linux专用

53.面对对象的三大特征

1. 封装(Encapsulation)

  • 定义:将对象的属性和方法包装在一起,并隐藏对象的内部实现细节
  • 目的:保护数据安全,提供统一的访问接口
  • 实现方式:使用访问修饰符(private、protected、public)控制访问权限
public class Student {private String name;  // 私有属性,外部无法直接访问private int age;// 公共方法提供访问接口public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {if (age > 0 && age < 150) {  // 数据验证this.age = age;}}}

2. 继承(Inheritance)

  • 定义:子类可以继承父类的属性和方法
  • 目的:代码复用,建立类之间的层次关系

3. 多态(Polymorphism)

  • 定义:同一个接口可以有多种不同的实现方式
  • 目的:提高代码的灵活性和可扩展性
  • 实现方式:方法重写、接口实现

54.fork和vfork的区别

1. 内存复制机制

  • fork():创建子进程时会复制父进程的整个地址空间(采用写时复制COW技术)
  • vfork():子进程与父进程共享同一个地址空间,不进行内存复制

2. 执行顺序

  • fork():父子进程可以并发执行,执行顺序不确定
  • vfork():父进程会阻塞等待,直到子进程调用exec()exit()

55.C++ 中深拷贝和浅拷贝的区别

浅拷贝只复制指针的值,多个对象会共享同一块动态分配的内存,适用于简单类型或无需独立管理资源的对象,可能导致内存泄漏。

深拷贝则复制指针指向的内存内容,每个对象拥有独立的内存副本,不会互相影响,适用于包含动态内存的对象。

56.函数重载的概念和本质

函数重载是 C++ 中的一个特性,允许在同一作用域中定义多个同名函数,但参数列表需要不同。函数重载的规则包括:函数名相同,参数列表不同,参数类型、数量或顺序有差异,返回值可以相同或不同。

57.什么是智能指针

智能指针是一种对象,用于自动管理和释放动态分配的的内存,避免内存泄露。

std::unique_ptr
  • 所有权独占:同一时间只能有一个unique_ptr指向特定资源,不可复制但可移动。
std::shared_ptr
  • 共享所有权:多个shared_ptr可以指向同一资源,通过引用计数管理生命周期。
std::weak_ptr
  • 弱引用:不增加引用计数,用于解决shared_ptr的循环引用问题。

58.什么是虚函数

虚函数主要用于实现多态性。它允许派生类重写基类中的函数

  • 无虚函数:总是调用指针类型对应的函数(静态绑定)
  • 有虚函数:调用实际对象类型对应的函数(动态绑定)

59.OSI七层模型和TCP IP四层模型

TCP,UDP在传输层,IP在网络层

数据封装过程

发送过程(封装):

应用层:  [数据]

            ↓

传输层:  [TCP/UDP头|数据]

            ↓  

网络层:  [IP头|TCP/UDP头|数据]

            ↓

网络接口层:[帧头|IP头|TCP/UDP头|数据|帧尾]

            ↓

        物理传输

接收过程(解封装):

网络接口层:去除帧头和帧尾

            ↓

网络层:  去除IP头,检查目标IP

            ↓

传输层:  去除TCP/UDP头,检查端口

            ↓

应用层:  获得原始数据

60.TCP粘包问题

粘包的原因包括 TCP 是流式传输,没有边界;数据发送的频率不固定;接收端读取不及时。

解决粘包的方法

制定固定长度的消息

使用特殊的分割符进行分割('\n' '\0')

在发送的时候带上长度的信息

制定对应的通信协议

以及关闭 TCP 的优化算法。

61.TCP三次握手四次挥手

TCP三次握手(建立连接)

客户端                    服务器

  |                        |

  |----① SYN=1,seq=x------>|  第一次握手:客户端请求连接

  |                        |

  |<---② SYN=1,ACK=1-------|  第二次握手:服务器确认并请求

  |     ack=x+1,seq=y      |

  |                        |

  |----③ ACK=1,ack=y+1---->|  第三次握手:客户端最终确认

  |                        |

  |      连接建立           |

TCP四次挥手(断开连接) 

客户端                    服务器
  |                        |
  |----① FIN=1,seq=u------>|  第一次挥手:客户端请求断开
  |                        |
  |<---② ACK=1,ack=u+1-----|  第二次挥手:服务器确认
  |                        |
  |<---③ FIN=1,seq=w-------|  第三次挥手:服务器请求断开
  |                        |
  |----④ ACK=1,ack=w+1---->|  第四次挥手:客户端确认
  |                        |
  |    TIME_WAIT(2MSL)     |
  |                        |
  |      连接关闭           |

62.自旋锁和互斥锁的区别

自旋锁允许线程在锁被占用时持续占用 CPU 资源(轮询),直到锁被释放,而互斥锁则会让线程挂起,等待锁被释放。

自旋锁适用于锁持有时间较短的情况,而互斥锁适用于锁持有时间较长的情况。自旋锁的开销较大,因为它需要反复检查锁的状态,而互斥锁的开销则体现在上下文切换上。

 63.什么是MQTT

MQTT 是一种轻量级的消息发布 / 订阅协议,适合低带宽、高延迟和不可靠的网络环境。

它支持发布 / 订阅模式,适合资源受限的设备,如 STM32 单片机。MQTT 基于 TCP/IP 协议,提供三种传输服务质量 (QoS) 级别。

支持心跳包保活机制,确保客户端和服务器在线状态。

64.vector和list的区别

vector(即std::vector)是一个动态数组,适合频繁的随机访问和少量的中间插入删除。

list(即std::list)是一个双向链表,适合频繁的中间插入删除和非随机访问。

vector的内存连续,随机访问效率高,而list的内存不连续,适合增删改查操作,但随机访问效率低。选择使用哪个容器,取决于具体的应用场景。

65.ARM 寄存器的重要性及其作用

ARM 架构中的寄存器分为通用目的寄存器和特殊寄存器。

通用目的寄存器 R0 到 R12 主要用于存储临时数据、函数参数和中间计算结果。

特殊寄存器中,R13 是栈指针寄存器,用于管理栈空间;

R14 是链接寄存器,用于存储函数调用的返回地址;

R15 是程序计数器,指向下一条要执行的指令。

66.DHCP 协议的基本原理和应用

DHCP 协议能够自动为网络设备分配 IP 地址,简化了网络配置,避免了地址冲突。其工作流程包括发现、提供、请求和确认四个步骤。DHCP 还支持租约机制,确保 IP 地址的有效使用。此外,DHCP 在家庭网络、局域网和无线网络中广泛应用,具有自动化配置、灵活性和易于扩展的优点。然而,DHCP 服务器故障可能导致网络设备无法获取 IP 地址,是其主要缺点。

67.IP地址,子网掩码,网关,DNS的作用

1. IP地址 (IP Address)

IP地址是网络中设备的唯一标识符
类似于:邮政地址中的详细地址

作用:
✅ 唯一标识网络中的设备
✅ 路由器根据IP地址转发数据包
✅ 实现端到端的网络通信

IPv4地址结构

IPv4地址格式:xxx.xxx.xxx.xxx (32位)

例子:192.168.1.100

地址分类:

A类:1.0.0.0    - 126.255.255.255  (大型网络)

B类:128.0.0.0  - 191.255.255.255  (中型网络)  

C类:192.0.0.0  - 223.255.255.255  (小型网络)

私有地址段:

A类私有:10.0.0.0      - 10.255.255.255

B类私有:172.16.0.0    - 172.31.255.255

C类私有:192.168.0.0   - 192.168.255.255

2. 子网掩码 (Subnet Mask)

作用和原理

子网掩码用于区分网络部分和主机部分

类似于:邮政地址中的省市区划分

作用:

✅ 划分网络ID和主机ID

✅ 确定同一子网内的设备范围

✅ 路由判断(本地还是远程通信)

示例:IP地址 192.168.1.100,子网掩码 255.255.255.0

二进制表示:
IP地址:    11000000.10101000.00000001.01100100
子网掩码:  11111111.11111111.11111111.00000000
                    ↑网络部分↑        ↑主机部分↑

网络ID:    11000000.10101000.00000001.00000000 = 192.168.1.0
广播地址:  11000000.10101000.00000001.11111111 = 192.168.1.255

可用主机地址范围:192.168.1.1 - 192.168.1.254 (254个主机)

 3. 网关 (Gateway)

网关工作流程

数据传输决策流程:

1. 主机A(192.168.1.100)要发送数据给目标IP

2. 计算目标IP是否在同一子网

   - 目标IP & 子网掩码 = 网络ID

   - 本机IP & 子网掩码 = 网络ID

   - 比较两个网络ID

3. 如果在同一子网:

   ┌──────────┐    直接通信    ┌──────────┐

   │  主机A   │ ←----------→ │  主机B   │

   │192.168.1.100│         │192.168.1.200│

   └──────────┘              └──────────┘

4. 如果不在同一子网:

   ┌──────────┐    ┌─────────┐    ┌──────────┐

   │  主机A   │-→ │  网关   │ -→ │ 外部网络 │

   │192.168.1.100│  │192.168.1.1│   │10.0.0.100│

   └──────────┘    └─────────┘    └──────────┘

4. DNS (Domain Name System) 

DNS查询流程:

1. 用户输入:www.baidu.com
2. 检查本地DNS缓存
3. 查询本地DNS服务器(通常是ISP提供)
4. 递归查询过程:

   客户端 → 本地DNS → 根域名服务器(.) → 顶级域服务器(.com) → 权威DNS(baidu.com) → 返回IP

详细流程:
┌─────────┐  ①查询www.baidu.com  ┌─────────────┐
│  客户端  │ ----------------→ │  本地DNS    │
└─────────┘                    └─────────────┘
                                      │ ②查询
                                      ↓
                               ┌─────────────┐
                               │  根DNS      │
                               │     .       │
                               └─────────────┘
                                      │ ③返回.com DNS
                                      ↓
                               ┌─────────────┐
                               │  .com DNS   │
                               └─────────────┘
                                      │ ④返回baidu.com DNS
                                      ↓
                               ┌─────────────┐
                               │ baidu.com   │
                               │ 权威DNS     │
                               └─────────────┘
                                      │ ⑤返回IP地址
                                      ↓
                               ┌─────────────┐
                               │  本地DNS    │ ⑥返回IP
                               │  (缓存)     │ -------→ 客户端
                               └─────────────┘

68.RAM、ROM 和 Flash 的区别

RAM 是一种随机存储器,断电后数据会丢失,主要用于存储计算机或设备运行时的临时数据,速度较快,CPU 可以直接访问。

ROM 是一种非易失存储器,断电后数据不会丢失,通常用于存储固件或启动代码

Flash 也是一种非易失存储器,断电后数据不会丢失,可以用于存储代码,分为 NAND Flash 和 NOR Flash 两种。 (SSD

69.Cache是什么

缓存,通常称为缓存(cache),是一种高速存储区域,位于中央处理器(CPU)和主存储器之间,用于存储最近或频繁访问的数据缓存可以显著提高数据访问速度,减少 CPU 等待时间,从而提高系统性能。

缓存的特点包括高速存储、临时性、城市结构(如一级缓存、二级缓存、三级缓存)和工作原理(缓存命中和缓存未命中)。缓存的常见用途包括 CPU 缓存、磁盘外部缓存、数据库缓存等。与 RAM 和磁盘相比,缓存容量较小但速度更快,RAM 容量更大但速度较慢,磁盘容量巨大但速度最慢。

70.常用的调试方法

  1. 串口调试:利用 printf 输出信息辅助调试。
  2. 仿真器调试:可设置断点、单步执行、查看寄存器。
  3. LED 灯调试:通过 LED 灯亮灭指示程序运行状态。
  4. 逻辑分析仪调试:捕捉通信协议数据波形进行分析。
  5. 内存调试:借助仿真器分析全局变量和内存状态。
  6. 示波器调试:与逻辑分析仪功能类似,用于信号分析。
  7. 看门狗调试:监测系统是否死机或陷入死循环。
  8. GDB 调试:在 LINUX 系统中用于断点和单步调试。

71.extern C的作用

1. 基本作用

问题背景:名称重整(Name Mangling)

// C++编译器会对函数名进行重整
void func(int x);
void func(double x);  // 函数重载// 编译后的符号可能变成:
// _Z4funci  (func with int parameter)
// _Z4funcd  (func with double parameter)// 而C编译器不会重整函数名:
// func 就是 func

extern "C" 的解决方案

extern "C" {void c_function(int x);  // 按C语言方式编译,不进行名称重整}// 等价于extern "C" void c_function(int x);

2. C++调用C语言库

头文件包装

// math_lib.h (C语言库头文件)
#ifndef MATH_LIB_H
#define MATH_LIB_H#ifdef __cplusplus
extern "C" {
#endif// C语言函数声明
int add(int a, int b);
double calculate_pi(void);
void init_math_library(void);#ifdef __cplusplus
}
#endif#endif // MATH_LIB_H
// main.cpp
#include <iostream>
#include "math_lib.h"  // C语言库int main() {// 直接调用C语言函数int result = add(10, 20);double pi = calculate_pi();std::cout << "Result: " << result << std::endl;std::cout << "PI: " << pi << std::endl;return 0;
}// 编译链接
// g++ main.cpp -L. -lmath_lib -o main

3. C语言调用C++函数

72.json格式的数据

JSON 是一种轻量级的数据交互格式,广泛应用于客户端和服务器之间的数据传输。它以键值对形式存在,支持字符串、数字、布尔值、数组和对象等多种数据类型。

{"user": {"id": 12345,"username": "john_doe","email": "john@example.com","profile": {"firstName": "John","lastName": "Doe","age": 30,"avatar": "https://example.com/avatar.jpg","isActive": true,"lastLogin": "2024-01-15T10:30:00Z"},"preferences": {"theme": "dark","language": "en","notifications": {"email": true,"push": false,"sms": true}},"roles": ["user", "premium"],"metadata": null}
}

73.TCP通信如何保证通信的可靠性

  1. TCP 会将数据分成小段,发送并重组,确保数据的完整性。
  2. 通过确认应答 ACK 机制,接收方确认接收数据,发送方在未收到确认时重发,确保数据送达。
  3. 滑动窗口和流量控制根据接收方处理能力动态调整数据传输量,避免网络拥堵。
  4. 拥塞控制通过慢启动和快速重传机制,判断网络状态,确保数据传输效率。
  5. 三次握手和四次挥手机制确保连接的正确建立和断开。

74.什么是原子变量


原子操作是一种不可分割的操作,要么执行成功,要么不执行,且在多线程或多进程中不可被打断。

Linux 中通过包含 std atomic 头文件,使用原子操作函数实现原子操作。

在 Linux 内核中,使用原子变量进行原子操作,保证数据的一致性。

原子操作的优点是开销小,缺点是只能用于简单的数值更新。


http://www.hkcw.cn/article/wCsKVVjdLY.shtml

相关文章

python可视化:端午假期旅游火爆原因分析

python可视化&#xff1a;端午假期旅游火爆原因分析 2025年的旅游市场表现强劲&#xff1a; 2025年端午假期全社会跨区域人员流动量累计6.57亿人次&#xff0c;日均2.19亿人次&#xff0c;同比增长3.0%。入境游订单同比大涨近90%&#xff0c;门票交易额&#xff08;GMV&#…

ubuntu22.04安装taskfile

sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -dsudo mv ./bin/task /usr/local/bin/测试 task --version

Ubuntu22.04 安装 Miniconda3

Conda 是一个开源的包管理系统和环境管理系统&#xff0c;可用于 Python 环境管理。 Miniconda 是一个轻量级的 Conda 发行版。Miniconda 包含了 Conda、Python和一些基本包&#xff0c;是 Anaconda 的精简版本。 1.下载安装脚本 在 conda官网 找到需要的安装版本&#xff0…

LRC and VIP

//首先排除所有数相等的情况,再把最大值放在一个组&#xff0c;那么最大值的gcd就等于其本身&#xff0c;再判断剩下的gcd是否等于最大值就可以了 #include<bits/stdc.h> using namespace std;const int N1e3100; int a[N]; map<int,int>mapp; int main(){int t;ci…

AI Agent开发第78课-大模型结合Flink构建政务类长公文、长文件、OA应用Agent

开篇 AI Agent2025确定是进入了爆发期,到处都在冒出各种各样的实用AI Agent。很多人、组织都投身于开发AI Agent。 但是从3月份开始业界开始出现了一种这样的声音: AI开发入门并不难,一旦开发完后没法用! 经历过至少一个AI Agent从开发到上线的小伙伴们其实都听到过这种…

统信 UOS 服务器版离线部署 DeepSeek 攻略

日前&#xff0c;DeepSeek 系列模型因拥有“更低的成本、更强的性能、更好的体验”三大核心优势&#xff0c;在全球范围内备受瞩目。 本次&#xff0c;我们为大家提供了在统信 UOS 服务器版 V20&#xff08;AMD64 或 ARM64 架构&#xff09;上本地离线部署 DeepSeek-R1 模型的…

6月2日day43打卡

复习日 作业&#xff1a; kaggle找到一个图像数据集&#xff0c;用cnn网络进行训练并且用grad-cam做可视化 进阶&#xff1a;并拆分成多个文件 任务写了两天&#xff0c;第一天找到一个数据集Stanford Cars Dataset&#xff08;斯坦福汽车数据集&#xff09;&#xff1a; 1. 基…

机器学习——聚类算法

一、聚类的概念 根据样本之间的相似性&#xff0c;将样本划分到不同的类别中的一种无监督学习算法。 细节&#xff1a;根据样本之间的相似性&#xff0c;将样本划分到不同的类别中&#xff1b;不同的相似度计算方法&#xff0c;会得到不同的聚类结果&#xff0c;常用的相似度…

蓝桥杯_DS18B20温度传感器---新手入门级别超级详细解析

目录 一、引言 DS18B20的原理图 单总线简介&#xff1a; ​编辑暂存器简介&#xff1a; DS18B20的温度转换与读取流程 二、代码配置 maic文件 疑问 关于不同格式化输出符号的使用 为什么要rd_temperature()/16.0&#xff1f; onewire.h文件 这个配置为什么要先读lo…

SuperMap GIS基础产品FAQ集锦(20250603)

一、SuperMap iDesktopX 问题1&#xff1a;这种投影坐标如何转换成China_2000的&#xff1f; 11.2.0 【解决办法】在数据源属性中&#xff0c;选择坐标系下的投影转换&#xff0c;然后指定转换结果的坐标系为China_2000 问题2&#xff1a;SuperMap iDesktopX 影像导出时&am…

【js 图片批量自定义打包下载】

压缩图片打包本地下载 一、依赖安转二、函数封装三、打包压缩四、应用五、示例图 一、依赖安转 打包工具 npm install file-saver --save npm install jszip --save二、函数封装 对图片进行处理 function getBase64Image(src) {return new Promise((resolve, reject) > …

如何轻松地将数据从 iPhone传输到iPhone 16

对升级到 iPhone 16 感到兴奋吗&#xff1f;恭喜&#xff01;然而&#xff0c;除了兴奋之外&#xff0c;学习如何将数据从 iPhone 传输到 iPhone 16 也很重要。毕竟&#xff0c;那些重要的联系人、笔记等都是不可或缺的。为了实现轻松的iPhone 到 iPhone 传输&#xff0c;我们总…

Adobe Acrobat——设置PDF打印页面的大小

1. 打开 PDF 文件&#xff1b; 2. 点击菜单栏的 “文件” → “打印”&#xff1b; 3. 在打印对话框中&#xff0c;点击 “属性”&#xff1b; 4. 点击 “布局”→ “高级”&#xff1b; 5. 点击 “纸张规格”&#xff0c;选择 “PostScript 自定义页面大小”&#xff0c;然后…

胜牌™全球成为2026年FIFA世界杯™官方赞助商

胜牌全球将首次与国际足联&#xff08;FIFA&#xff09;旗舰赛事建立合作关系。 此次赞助恰逢美国首个润滑油品牌即将迎来160周年之际&#xff0c;其国际扩张步伐正在加快。 在这项全球顶级赛事筹备期间&#xff0c;胜牌全球将通过各种富有创意的零售和体验活动与球迷互动。 …

mpg123在MSVC编译器中使用。

官网下载&#xff1a; 下载后打开以下窗口程序&#xff1a; 在此窗口程序中打开所下载的mpg123文件夹。在此文件夹中输入以下命令&#xff1a; dumpbin /EXPORTS libsyn123-0.dll > libsyn123-0.exports lib /DEF:libsyn123-0.def /OUT:libsyn123-0.lib /MACHINE:x64其中…

【LangServe部署流程】5 分钟部署你的 AI 服务

目录 一、LangServe简介 二、环境准备 1. 安装必要依赖 2. 编写一个 LangChain 可运行链&#xff08;Runnable&#xff09; 3. 启动 LangServe 服务 4. 启动服务 5. 使用 API 进行调用 三、可选&#xff1a;访问交互式 Swagger 文档 四、基于 LangServe 的 RAG 应用部…

苍穹外卖--HttpClient

1.介绍 HttpClient是Apache Jakarta Common下的子项目&#xff0c;可以用来提供高效的、最新的、功能丰富的支持HTTP协议的客户端编程工具包&#xff0c;并且它支持HTTP协议最新的版本和建议 依赖&#xff1a; 核心API&#xff1a; ①HTTPClient ②HTTPClients ③Closeabl…

最佳实践 | 璞华易研“PLM+AI智能研发平台”,助力汉旸科技实现高新材料“数据驱动研发”

合作动态 | PURVAR 日前&#xff0c;汉旸科技与璞华科技达成战略合作&#xff0c;正式引入璞华易研PLMAI智能研发平台。双方基于行业技术需求与数字化转型目标&#xff0c;快速完成研发全流程数字化管理框架的顶层设计与蓝图规划&#xff0c;为技术迭代与产品创新奠定坚实的数…

MongoDB数据库学习

学习链接&#xff1a;https://www.runoob.com/mongodb/mongodb-tutorial.html 图解MongoDB数据库学习路线指南 MongoDB初级 1. 基本概念学习 一定要记住的概念&#xff1a; 文档是一组键值(key-value)对(即 BSON)。 集合就是 MongoDB 文档组&#xff0c;类似于 RDBMS &…

软考 系统架构设计师系列知识点之杂项集萃(79)

接前一篇文章&#xff1a;软考 系统架构设计师系列知识点之杂项集萃&#xff08;78&#xff09; 第141题 软件测试一般分为两个大类&#xff1a;动态测试和静态测试。前者通过运行程序发现错误&#xff0c;包括&#xff08;&#xff09;等方法&#xff1b;后者采用人工和计算机…