嵌入式面经

一、C语言

1.++i和i++区别

前置自增(++i

前置自增运算符会先将变量 i 的值增加1,然后再使用增加后的值。

后置自增(i++

后置自增运算符会先使用变量 i 的当前值,然后再将变量 i 的值增加1。

#include <stdio.h>

int main() {
    int i = 5; 
// 前置自增
printf("Using ++i: %d\n", ++i); // 先增加1,后使用,输出6
printf("After ++i: %d\n", i);   // 输出6

// 重新设置i的值
i = 5;
// 后置自增
printf("Using i++: %d\n", i++); // 先使用,后增加1,输出5
printf("After i++: %d\n", i);   // 输出6
return 0;
}

2.存储类型相关关键字

  • auto:声明自动变量(默认存储类型)。

  • extern:声明外部变量或函数。

  • register:声明寄存器变量,提示编译器将变量存储在寄存器中。

  • static:声明静态变量或静态函数。

  • const:声明常量,不允许修改。

  • volatile:声明易变变量,提示编译器不优化该变量。

  • restrict:用于指针声明,提示编译器该指针是唯一访问某对象的方式(C99标准引入)。

1.关键字static的作用是什么

其主要作用取决于它所修饰的上下文,可以总结如下:

(1)、用于隐藏

静态函数(Static Functions)

  • 在函数声明前面加上 static 关键字将该函数声明为静态函数。
  • 静态函数只能在当前文件中使用,它们不能被其他文件中的函数调用
  • 静态函数通常用于限制函数的作用域,提高代码的模块化和安全性
static void helper_func() {
    // 这是一个静态函数,只能在当前文件中调用
}

(2)、保持变量内容的持久

静态变量(Static Variables)

  • 仅限于声明它的文件内使用,不被其它文件访问。
  • 在程序执行期间只被初始化一次,而且在函数调用结束后也不会销毁,而是保留其值和状态。
  • 如果没有显式初始化,静态变量会被自动初始化为0(对于数值类型)或空指针(对于指针类型)
void func() {
    static int count = 0;  // 静态变量,此赋值语句从来没有执行过,不调用为0;只有调用才会执行,并且不会被销毁
    count++;
    printf("Count: %d\n", count);
}
2.关键字const的作用是什么

(1)、修饰变量:const关键字用于声明常量,即在程序运行期间其值不能被改变的变量。

const int a = 10;
// a = 20; // 错误:不能修改const变量的值

(2)、修饰指针

(3)、修饰函数参数:使用const关键字修饰函数参数,表示该参数在函数内部不能被修改。这对于传递数组或指针时尤其有用,可以防止函数意外修改参数的值。

void func(const int *p) {
    // *p = 20; // 错误:不能通过指针修改指向的内容
}

void func2(const int arr[], int size) {
    // arr[0] = 20; // 错误:不能修改数组内容
}

(4)、修饰返回值:使用const修饰函数返回值,表示返回的值不能被修改。常见用法是在返回指向常量的指针时使用const

const char* getString() {
    return "Hello, World!";
}

int main() {
    const char *str = getString();
    // str[0] = 'h'; // 错误:不能修改返回的字符串内容
    printf("%s\n", str);
    return 0;
}

二.Linux

1.TCP/UPD的区别 面向连接和面向无连接

TCP(传输控制协议Transmission Control Protocol)

特点:

  • 面向连接

    在传输数据之前,必须建立连接(三次握手)。

    1. 第一次握手

      客户端发送一个SYN(synchronize)包到服务器,并请求建立连接。包中包含一个初始序列号(Sequence Number, 简称Seq),记为SYN=Seq

    2. 第二次握手

      服务器收到SYN包后,发送一个SYN-ACK(synchronize-acknowledgment)包给客户端,表示同意建立连接。包中包含服务器的初始序列号SYN=Seq_Server和客户端序列号的确认号(Acknowledgment Number, 简称Ack),记为ACK=Seq+1

    3. 第三次握手

      客户端收到SYN-ACK包后,发送一个ACK包给服务器,表示连接建立。包中包含客户端序列号的确认号,记为ACK=Seq_Server+1

      此时,客户端和服务器之间的连接已建立,双方可以开始传输数据。

    传输完数据后,必须关闭连接(四次挥手)。四次挥手是TCP连接终止的过程,它确保了客户端和服务器之间的连接安全地关闭。

    1. 第一次挥手

      客户端发送一个FIN(finish)包到服务器,表示客户端的数据已经发送完毕,请求关闭连接。。

      包中包含一个序列号,记为FIN=Seq_Client。发送FIN包后,客户端进入FIN-WAIT-1状态。

    2. 第二次挥手

      服务器收到FIN包后,发送一个ACK包给客户端,确认收到客户端的FIN请求。

      包中包含客户端序列号的确认号,记为ACK=Seq_Client+1。发送ACK包后,服务器进入CLOSE-WAIT状态,客户端进入FIN-WAIT-2状态。

      此时,服务器仍然可以发送未传输完的数据给客户端。

    3. 第三次挥手

      服务器在完成所有数据传输后,发送一个FIN包到客户端,表示服务器的数据也已经发送完毕,请求关闭连接。

      包中包含一个序列号,记为FIN=Seq_Server。发送FIN包后,服务器进入LAST-ACK状态。

    4. 第四次挥手

      客户端收到FIN包后,发送一个ACK包给服务器,确认收到服务器的FIN请求。

      包中包含服务器序列号的确认号,记为ACK=Seq_Server+1。发送ACK包后,客户端进入TIME-WAIT状态。服务器在收到ACK包后进入CLOSED状态。

    此时,客户端和服务器之间的连接已关闭。

  • 可靠性

    提供可靠的数据传输,确保数据包按顺序到达并且没有丢失。

    使用确认机制,数据包到达接收方后,接收方需要发送确认应答。

    如果发送方没有收到确认应答,会重新发送数据包。

  • 流量控制

    使用滑动窗口机制来控制发送方发送数据的速率,防止网络拥塞。

  • 拥塞控制

    使用多种拥塞控制算法(如慢启动、拥塞避免、快速重传和快速恢复)来控制网络流量,防止网络过载。

应用场景:

  • 需要高可靠性的数据传输,如文件传输、电子邮件、网页浏览等。
  • 例如:HTTP/HTTPS、FTP、SMTP、POP3。

UDP(用户数据报协议User Datagram Protocol)

特点:

  • 面向无连接

    在传输数据之前,不需要建立连接。

    发送方直接将数据包发送给接收方。

  • 不可靠性

    不保证数据包按顺序到达,也不保证数据包不丢失。

    没有确认机制,发送方发送数据包后,不会等待接收方的确认。

  • 无流量控制和拥塞控制

    UDP不提供流量控制和拥塞控制机制。

  • 轻量级

    UDP头部开销小,传输速度快。

应用场景:

  • 需要快速传输,且能够容忍少量数据丢失的场景,如视频直播、在线游戏、语音通信等。
  • 例如:DNS、DHCP、SNMP、RTP。

2.UART、SPI、I2C对比

对比项UARTSPII2C
信号线数目3根,RX、TX、GND4根,SDO、SDI、SCLK、SS2根,SDA、SCLK
设备从属关系——存在主从设备。SPI用片选信号选择从机存在主从设备。IIC用地址选择从机。
通信方式全双工通信全双工通信半双工通信
通信速率速度慢比I2C总线要快,速度可达到几MbpsI2C的速度比SPI慢
应用领域1、UART常用于控制计算机与串行设备的芯片2、就是我们经常所说的串口,基本都用于调试。主要应用在EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间I2C一般是用在同一个板子上的2个IC之间的通信 ,它可以替代标准的并行总线,连接各种集成电路和功能模块。
传输距离9600 bps下,可以达到50米左右,115200 bps下,传输距离通常在15米左右通常推荐的传输距离在1米以内,在特定条件下(如降低时钟频率、使用低电容电缆),可以达到10米I2C需要有双向IO的支持,而且使用上拉电阻,抗干扰能力较弱,一般用于同一板卡上芯片之间的通信,较少用于远距离通信。通常推荐的最大传输距离在1米左右。使用低电容电缆和缓冲器,可以扩展到10米以上。
通信特征异步,一帧可以传5/6/7/8位同步SPI允许数据一位一位的传送,甚至允许暂停。从最高位开始传。同步,电平信号,一次连续8bit。从最高位开始传
协议复杂度结构比较复杂SPI实现要比UART简单,UART需要固定的波特率,就是说两位数据的间隔要相等,而SPI则无所谓,因为它是有时钟的协议。协议比SPI复杂,但是连线比标准的SPI要少
对比在点对点的通信中,SPI接口不需要进行寻址操作,且为全双工通信,显得简单高效。在多个从器件的系统中,每个从器件需要独立的使能信号,硬件上比I2C系统要稍微复杂一些。

全双工通信半双工通信区别:

同时传输能力:

  • 全双工:可以同时进行发送和接收,效率高。
  • 半双工:发送和接收不能同时进行,效率较低。

硬件复杂度:

  • 全双工:需要双向传输线路,硬件复杂度较高。
  • 半双工:只需要单向传输线路,硬件实现简单。

通信效率:

  • 全双工:传输效率高,无需等待。
  • 半双工:传输效率较低,需要等待发送和接收的时机。

同步通信异步通信区别:

  • 同步通信:需要发送方和接收方在数据传输之前进行时钟同步,数据传输按照固定的时钟周期进行。

  • 异步通信:发送方和接收方之间没有共享的时钟信号,数据传输可以在任何时候进行,不需要固定的时钟周期。


二.数据结构

1.数组和链表的区别

数组

  • 内存效率高
  • 适合于固定大小且需要随机访问的场景,数组的大小固定,一旦访问超出数组边界,容易出现内存访问越界问题。

链表

  • 空间利用率低
  • 灵活性高;适合于动态大小且需要频繁插入和删除操作的场景,由于节点通过指针连接,不会出现内存访问越界问题。
  • 23
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值