Skip to content

Latest commit

 

History

History
2328 lines (1060 loc) · 75.9 KB

技术面试问题.md

File metadata and controls

2328 lines (1060 loc) · 75.9 KB

系统IO和标准IO的区别(模拟面试)

区别一表示文件的方式不同
        系统IO采用文件描述符来表示文件
        标准IO采用FILE*来表示文件

区别二标准输入标准输出标准错误输出不同
    系统IO        0         1            2(使用宏定义)
                #define  STDIN_FILENO		0   标准输入
                #define  STDOUT_FILENO		1   标准输出
                #define  STDERR_FILENO		2   标准错误输出
    标准IO       stdin   stdout      stderr(使用FILE*类型的变量)
                FILE *stdin      	标准输入
                FILE *stdout   	    标准输出
                FILE *stderr     	标准错误输出

区别三缓冲区的区别
        系统IO没有缓冲,所用函数为open()  write()
        标准IO带缓冲区,所用函数为fopen()  fwrite()
一般来说标准IO读写的速度效率要比系统IO要高
          如果是打开读写硬件传感器的驱动一般都是使用系统IO

区别四系统IO是Linux内核的API接口标准IO是C语言的库函数

标准IO为什么比系统IO效率高(模拟面试延伸)

	因为标准IO使用缓存技术当数据写入时并没有立即把数据交给内核而是先放在缓存区中当缓存区满时会一次性把缓冲区中的数据交给内核这样就减少了内核态与用户态的切换次数而系统IO每写一次数据就要进入一次内核态这样就浪费了大量时间进行内核态与用户态的切换因此用时更长如果为系统IO设置更大的缓冲区它会比标准IO更快

系统IO和标准IO打开文件的方式(模拟面试延伸)

系统IOO_RDONLY   只读
O_WRONLY   只写
O_RDWR     可读写
O_APPEND   以追加的方式打开文件
O_CREAT    新建文件
O_EXCL     跟O_CREAT配合使用,表示如果文件存在就失败退出不存在就新建
O_TRUNC    跟O_CREAT配合使用,表示如果文件存在就清空覆盖掉原来的文件标准IOr  --只读的方式打开文件
r+ --可读写的方式
w  --可写的方式打开
w+ --可读写的方式如果文件不存在就新建存在就清空覆盖掉
a  --可写的方式追加
a+ --可读写的方式追加 

read和write返回值(扬智科技)

read返回值>01 等于给定字节数2 小于给定字节数可能原因如下:
				(1)在读到小于指定字节数时就已经收到了EOF返回已经读到的数据。
				(2)在读入部分数据时被信号打断返回已经读到的数据返回值=0说明读到了文件尾EOF或者socket对端关闭返回值<01 fd设定为非阻塞且要被阻塞时立即返回-12 fd设定为阻塞在读数据之前被打断返回-1write返回值>01 等于给定字节数2 小于给定字节数可能原因如下:
				(1)底层物理介质上没有足够空间。
				(2)创建的文件指定了最大字节数不能再往里面添加数据。
				(3)已经写了部分数据但被中断信号打断返回中断前写入的字节数返回值=0如果有设定相应的error说明有相对应的失败原因若无则没有任何影响返回值<01 fd设定为非阻塞但是write将会被阻塞的情况下返回-12 fd设定为阻塞在一个字节都还未写入之前被信号打断返回-13 fd是pipe或者socket的文件描述符对端的读端关闭

系统IO和标准IO常用的函数的函数名(移远通信面试)

系统IOopenwritereadclose
lseek(文件偏移改变)
stat(获取文件属性)
chmod(修改文件权限)
access(判断文件是否存在)
perror(打印分析错误信息)
dup/dup2(文件重定向给原来的文件重新分配一个新的文件描述符)
sprintf(字符串的拼接)
sscanf(字符串的拆分)
mmap(内存映射)
munmap(解除映射)

标准IOfopenfreadfwritefclose
fseek(文件偏移改变)
ftell(返回当前位置距离起始位置的字节数)
rewind(将文件偏移挪到起始位置)
fprintf(按照指定格式把数据合并写入到文件中)
fscanf(按照指定格式把数据读取出来)
fgets(按行读取数据)
feof(判断是否到文件末尾)返回1则代表到达文件末尾
fflush(主动刷新缓冲区)
gets/puts/getc/putc/getchar/putchar略

分段拷贝的意义(模拟面试延伸、纳思达面试)

直接进行大文件/大目录的全部拷贝可能会出现内存开销不够或者由于特殊情况导致拷贝过程突然中断的情况

OSI七层模型(移远通信面试)

1 应用层 		作用开发特定的应用程序需要用到其中的部分协议   http协议(超文本传输协议)  ftp协议(文件传输协议)  telnet(远程登录)
2 会话层 		作用建立会话对数据加密解密
3 表示层 		作用数据的封装解析   
4 传输层 		作用解决数据在网络中传输的问题  tcp协议和udp协议
5 网络层		作用解决路由问题(数据采取何种路径发送出去最优)ip协议
6 数据链路层	作用开发网卡的驱动(需要深入了解这个层次的协议)
7 物理层      作用网络接口真实的网卡

多路复用

概念多路复用是计算机中用来监测IO口是否有数据可读可写的一种技术
作用多路复用是用于监测多个文件描述符的状态

相关接口函数1 int select(int maxfd,fd_set *readset,fd_set *writeset,fd_set *exceptset,const struct timeval *timeout);//多路复用
2 void FD_ZERO(fd_set *fdset);          //清空集合
3 void FD_SET(int fd, fd_set *fdset);   //将fd加入集合fdset中
4 void FD_CLR(int fd, fd_set *fdset);   //将fd从集合中删除
5 int FD_ISSET(int fd, fd_set *fdset);  //判断fd在不在集合fdset中(在集合中返回1,不在集合中返回0)

使用TCP协议如何获取IP地址及端口号(他人移远通信面试)

首先要申请一个struct sockaddr_in类型的变量用于存放IP地址和端口号这个变量中要用到三个成员1 sin_family成员存放的是IPV4或者IPV6的标记2 sin_addr.s_addr成员中存放的是本地主机的IP使用htonl函数获取客户端获取服务器的IP地址是通过inet_addr函数来获取的3 sin_port成员存放的是端口号使用htons函数获取随后再创建一个struct sockaddr_in类型的变量来存放对方的IP和端口号创建的这两个变量会在accept和connect函数中使用到

TCP协议的三次握手与四次握手(模拟面试、纳斯达面试)

三次握手是建立连接时使用的
第一次客户端给服务器发送一个SYN(同步信号)
第二次服务器收到后回复客户端发送ACK(应答信号)和SYN(同步信号)
第三次客户端收到第二次握手的信号时再一次发送ACK(应答信号)给服务器

四次握手是断开连接时使用的
第一次客户端发送FIN(结束信号)至服务器
第二次服务器收到FIN信号后回复ACK(应答信号)给客户端
第三次服务器在第二次握手后延时一会再一次发送一个FIN(结束信号)给客户端
第四次客户端收到来自服务器的第二第三次握手后发送ACK(应答信号)给服务器

TCP结束时为什么要四次握手(模拟面试延伸)

详细叙述问题三次握手时第二次握手的时候ACK和SYN信号是同时发送的而在四次握手时为什么服务器在接收到客户端的FIN信号后发送回去的ACK和FIN信号要分开并延迟一会分成两次握手发送过去因为TCP有一种连接方式叫做半关连接指的是客户端发送了FIN信号表明客户端不再发送数据了但是还能接收数据此时服务器也未必全部数据都已经发送完毕给客户端在这时后服务器可以选择立即发送FIN信号表示关闭也可以选择发送数据结束后再发送FIN信号表示关闭所以服务器的ACK和FIN一般会分为两次发送故导致比三次握手多了一次

TCP协议为什么是三次握手而不是二次握手(玄武云 简答)

1 为了防止已经失效的连接请求报文突然又传送到了服务器从而导致不必要的错误和资源的浪费。
    
(举例若客户端发送的第一个连接请求没有丢失但由于在网络中滞留的时间太长了此时由于客户端久久没有收到确认报文以为服务器没有收到此时重新向服务器发送这条报文此后客户端和服务器通过两次握手完成连接传输数据然后关闭连接此时之前滞留的那一次请求因为网络通畅了到达了服务器此时就又一次建立了连接导致不必要的错误和资源的浪费。)

2 二次握手只能保证单向连接是通畅的因为TCP是一个双向传输协议只有经过三次握手才能保证双向都可以接受到对方发送的数据

使用TCP协议进行编程时客户端与服务端各种函数的使用以及实际发生的先后顺序(CVTE一面、海康威视面试)

服务端1 使用socket函数生成套接字
			2 利用bind函数绑定IP和端口号
			3 使用listen函数进行对客户端的监听
			4 使用accept函数接受客户端的连接请求
			5 使用recv和send进行收发信息
客户端1 使用socket函数生成套接字
			2 利用bind函数绑定IP和端口号(这一步在客户端中不是必须的,若不绑定则linux的内核会自动分配端口绑定,UDP同理) 
			3 使用connect函数拨号连接服务器(三次握手)
			4 使用recv和send进行收发信息
	顺序先运行服务端服务端进行了socket函数bind函数listen函数后卡在accept函数处等待客户端而客户端运行后运行了socket函数bind函数(可有可无)、以及connect函数通过connect函数连接服务器此时服务器的accept函数接收到了连接请求不再阻塞进入recv和send的收发信息此时客户端也进入了recv和send函数的收发信息。 
    
	(延伸UDP协议socket函数与bind函数调用后就可调用他的sendto和recvfrom函数收发信息但是UDP也是能使用connect函数的但它不是进行三次握手而是检查是否存在立即可知的错误例如连接一个不可达到的地址。)

使用TCP/UDP时,客户端是否要使用bind函数绑定(CVTE一面)

在服务器中是必须要使用bind函数将套接字和IP地址端口绑定的但这一步在客户端中不是必须的若不绑定则linux的内核会自动分配端口绑定

TCP和UDP的概念、区别以及优缺点(CVTE一面、玄武云 简答、海康威视面试)

TCP是传输控制协议是面向连接的通讯协议通过三次握手建立连接通讯完成时四次握手一般应用在对安全性完整性有严格要求的场景FTPSMTPHTTP等优点TCP具有高可靠性确保传输数据的正确性不出现丢失或者乱序
缺点TCP相对于UDP速度慢一点效率低而且要求系统资源较多每个链接都会占用系统的CPU内存等硬件资源UDP是用户数据报协议是面向无连接的通讯协议
优点UDP速度快操作简单要求系统资源较少缺点不可靠可能会出现丢包乱序数据不完整区别1 TCP是面向连接的传输控制协议而UDP是用户数据报协议提供了无连接的数据报服务2 TCP保证了数据的正确性UDP可能会丢包3 UDP具有较好的实时性工作效率比TCP协议高4 每一条TCP连接都是只能一对一的而UDP可以支持一对一一对多多对一和多对多的交互通信5 TCP对系统资源要求较多UDP对系统资源要求较少

TCP为什么是可靠的(海康威视面试)

1 数据传输之前会有三次握手来进行连接2 在数据传输时候有确认滑动窗口超时重传拥塞控制之类机制3 数据传输之后会进行四次挥手断开连接来节约系统资源第二点具体1 应用数据被分割成TCP认为最适合发送的数据块2 TCP给发送的每一个包进行编号接收方对数据包进行排序把有序数据传送给应用层3 校验和TCP 将保持它首部和数据的检验和这是一个端到端的检验和目的是检测数据在传输过程中的任何变化如果收到段的检验和有差错TCP 将丢弃这个报文段和不确认收到此报文段4 TCP 的接收端会丢弃重复的数据5 利用滑动窗口实现流量控制TCP连接的每一方都有固定大小的缓冲空间TCP 的接收端只允许发送端发送接收端缓冲区能接纳的数据当接收方来不及处理发送方的数据能提示发送方降低发送的速率防止包丢失TCP 使用的流量控制协议是可变大小的滑动窗口协议。(TCP利用滑动窗口实现流量控制)
6 拥塞控制当网络拥塞时减少数据的发送7 ARQ协议也是为了实现可靠传输的它的基本原理就是每发完一个分组就停止发送等待对方确认在收到确认后再发下一个分组8 超时重传当TCP发出一个段后它启动一个定时器等待目的端确认收到这个报文段如果不能及时收到一个确认将重发这个报文段

TCP和UDP一次性最多传输多少个字节(网上答案不唯一,不一定对)

一次传输最多1500字节,但是1	TCP只能1480字节因为IP数据报首部有20个字节2 	UDP只能1472字节因为在IP数据报首部20个字节的基础上UDP数据报首部还有8个字节所以比TCP少8个

UDP点播、广播、组播(海康威视面试)

单播(点播):一对一广播一对多发送给局域网所有的主机组播(多播):广播的一种特殊形式一对多发送组播组里面的所有的主机通过 setsockopt函数设定UDP的套接字的作用1 不做任何设置为一对一点播2 广播则是在setsockopt函数中使用SO_BROADCAST的宏定义对套接字进行广播设置3 组播则是在广播的基础上组播端要使用组播地址(D类地址224.0.0.0到239.255.255.255)进行设置接收端要使用该组播地址通过setsockopt函数加入组播组中达到组播的功能

ping命令的作用和原理(CVTE一面)

ping命令是用来探测本机与网络中另一主机之间是否可达的命令即是否可以进行通信ping命令是通过ICMP协议来工作的在运行的时候ping命令会发送一份ICMP回显请求报文给目标主机并等待目标主机返回ICMP回显应答若源主机在一段时间内收到了目标主机的回显应答则证明两台主机之间网络是可达的

ICMP协议(CVTE一面延伸)

	ICMP协议是通过IP协议来进行发送的它封装在IP的包中由于IP协议是一种无连接不可靠的数据包协议它并不能保证数据一定被送达而ICMP协议就是为了保证数据送达而引入的模块浅显一点的说法就是当传送的IP数据包发送异常的时候ICMP就会将异常信息封装在包中然后回传给源主机随后源主机得到该异常信息后会对发送异常的数据再一次发送
1 DNS协议将域名转换为IP地址用到了DNS
2 ARP协议获取IP地址后通过ARP解析服务获得MAC地址
3 ICMP协议ping功能测试另一台主机与本机是否互相可达程序发送一份ICMP回显请求给目标主机并等待返回ICMP回显应答不会用到TCP因为没有涉及到数据的传输

linux系统中文件的类型及其标志(CVTE笔试)

下列例子权限全为777
-rwxrwxrwx	普通文件开头为-(普通文件)
drwxrwxrwx	目录文件开头为d(文件夹)
crwxrwxrwx	字符设备文件开头为c(用于驱动开发对应硬件设备实际上并不存在与磁盘中是文件系统虚拟出来的)
brwxrwxrwx	块设备文件开头为b(用于驱动开发对应硬件设备实际上并不存在与磁盘中是文件系统虚拟出来的)
lrwxrwxrwx	符号链接文件开头为l(类似于windows的快捷方式分为软链接和硬链接具体区别看笔记)
srwxrwxrwx	套接字文件开头为s(用于进程间通信实际上是网络通信具体例子有三次握手和四次握手)
prwxrwxrwx	管道文件开头为p(用于进程间的通信一般是由有名管道产生)

字符设备、块设备(特点)(扬智科技面试)

字符设备1 一个字节一个字节读写的设备2 读取数据需要按照先后数据顺序读取)。
3 常见的字符设备有鼠标键盘串口控制台和LED设备4 每个字符设备在/dev目录下对应一个设备文件linux用户程序通过设备文件(或称设备节点)来使用驱动程序操作字符设备块设备1 数据以固定长度进行传输比如512K2 从设备的任意位置可跳读取但实际上块设备会读一定长度的内容而只返回用户要求访问的内容所以随机访问实际上还是读了全部内容3 块设备包括硬盘磁盘U盘和SD卡等4 每个块设备在/dev目录下对应一个设备文件linux用户程序通过设备文件(或称设备节点)来使用驱动程序操作块设备5 块设备可以容纳文件系统比如磁盘

线程的相关函数的函数名(移远通信面试、扬智科技面试)

线程的创建 pthread_create
线程的退出 pthread_exit
线程的等待回收 pthread_join
线程的取消 pthread_cancel

线程的互斥锁(模拟面试延伸)

作用协调多个线程对于共享资源的访问保证任意时刻只有一个线程在访问共享资源(临界区资源)

原理: 通过上锁和解锁操作实现任意时刻只有一个线程在访问共享资源某个线程如果对共享资源上锁了那么其他线程都无法使用该共享资源只有等到解锁以后其他线程才能使用共享资源

特点多个线程使用同一把锁谁先上锁那么后面上锁的线程都会阻塞

死锁定义互斥锁上完锁以后没有对应的解锁操作导致这把锁任何线程都无法使用产生死锁常见的原因1 程序员粗心大意忘记解锁
解决方法把解锁操作代码加上即可
2 线程刚上锁还没有来得及解锁就被取消了
解决方法:
  	(1)可以把线程设置成不能被取消
  	(2)使用pthread_cleanup_push函数设置线程取消的时候去调用解锁操作。(注意pthread_cleanup_push要和pthread_cleanup_pop配合使用因为这两个函数其实是宏定义,push包含左花括号,pop包含右花括号必须成对使用)

线程的条件变量(模拟面试延伸)

特点不能单独使用需要配合互斥锁实现线程的协调控制

作用满足某个条件的时候可以用条件变量去阻塞或者唤醒线程(顾名思义就是满足某个条件之后利用条件变量去阻塞/解除阻塞线程)

线程池

1.本质: 多个线程组成的一个集合目的为了并发执行任务定义时是一个结构体成员有线程数量,线程ID,互斥锁,条件变量,任务数量,结束标志位等2.线程池的关键技术
(1)万能函数指针(通用函数指针):
	void *(*p)(void *)
	注意事项函数的参数个数超过1个 --参数打包成结构体多个参数就变成一个参数(全部包含在结构体里面了)
	原理该函数需要用到互斥锁在完成一个任务后减少任务数量,解锁后继续下一个任务,还要用到条件变量在任务全部完成时通过判断任务数量和结束标志位退出。
(2)封装线程池有关的接口函数
	三大基本函数需要我们去封装
	第一个初始化线程池
	原理通过对线程池结构体中的成员初始化让线程池进入工作模式随后使用循环创建对应数量的线程第二个添加任务
	原理通过动态分配内存准备新的内存空间分配给新的任务在添加任务时利用互斥锁上锁防止任务函数完成任务时减少任务数量带来的冲突将任务尾插到任务链表中并且对线程池结构体中各个成员变量进行更新第三个线程池的销毁(回收线程想办法让线程的任务函数退出)
	原理通过改变线程池结构体成员变量中的结束标志位令所有线程能够退出随后在任务函数中开始退出线程并在这个线程池销毁函数中回收所有线程另外两个接口函数增加线程删除线程

内核链表kernellist(模拟面试)

只适用于linux系统它是linux中专用的一种链表(本质上就是个双向循环链表)

优势1 内核链表把指针操作封装成了函数或者宏定义(方便你直接使用隐藏了指针操作的细节)
       2 数据和指针做了剥离数据域由程序员自己来定义需要的数据类型指针域不需要程序员来操心linux已经定义了一个结构体struct list_head专门用来存放两个指针(next,prev)。

	linux还把这两个指针相关的操作(增删改查)都封装成了函数或者宏定义给程序员直接调用。(比如初始化头结点INIT_LIST_HEAD(x),尾插list_add_tail(x,x),删除list_del(x),遍历list_for_each_entry(x,x,x))

ARM中的指令集(优特科技笔试延伸)

1 ARM指令集
2 Thumb指令集(是ARM体系结构的变种带来了更高的代码密度)

Cortex-A53有多少个核心(GEC6818开发板)(扬智科技面试)

核心数量1-4
虚拟地址48
物理地址40
页表大小4K16K64K1M2M1G

uboot(扬智科技面试)

作用uboot 属于bootloader的一种是用来引导启动内核的它的最终目的就是从flash中读出内核放到内存中启动内核过程第一阶段硬件的初始化
第二阶段1 从flash中读出内核
			2 移动内核到合适的加载位置
		   	3 启动内核

Linux内核是什么(扬智电子简答延伸)

1 内核指的是一个提供硬件抽象层磁盘及文件系统控制多任务等功能的系统软件2 内核是一个操作系统的核心是操作系统最基本的部分它负责管理系统的进程内存设备驱动程序文件和网络系统等决定着系统的性能和稳定性3 直接对硬件操作是非常复杂的所以内核通常提供一种硬件抽象的方法来完成这些操作硬件抽象隐藏了复杂性为应用软件和硬件提供了一套简洁统一的接口使程序设计更为简单

Linux内核的作用(扬智电子简答延伸)

1 进程管理内核负责创建和销毁进程, 并处理它们与外部世界的联系(输入和输出),不同进程间通讯(通过信号管道或者进程间通讯原语)对整个系统功能来说是基本的也由内核处理另外调度器控制进程如何共享CPU是进程管理的一部分更通常地内核的进程管理活动实现了多个进程在一个单个或者几个CPU 之上的抽象2 内存管理计算机的内存是主要的资源处理它所用的策略对系统性能是至关重要的内核为所有进程的每一个都在有限的可用资源上建立了一个虚拟地址空间内核的不同部分与内存管理子系统通过一套函数调用交互从简单的malloc/free对到更多更复杂的功能3 文件管理Linux 在很大程度上基于文件系统的概念;几乎Linux中的任何东西都可看作一个文件内核在非结构化的硬件之上建立了一个结构化的文件系统结果是文件的抽象非常多地在整个系统中应用另外Linux 支持多个文件系统类型就是说物理介质上不同的数据组织方式例如磁盘可被格式化成标准Linux的ext3文件系统普遍使用的FAT文件系统或者其他几个文件系统4 驱动管理几乎每个系统操作终都映射到一个物理设备上除了处理器内存和非常少的别的实体之外全部中的任何设备控制操作都由特定于要寻址的设备相关的代码来进行这些代码称为设备驱动内核中必须嵌入系统中出现的每个外设的驱动从硬盘驱动到键盘和磁带驱动器5 网络管理网络必须由操作系统来管理因为大部分网络操作不是特定于某一个进程进入系统的报文是异步事件报文在某一个进程接手之前必须被收集识别分发系统负责在程序和网络接口之间递送数据报文它必须根据程序的网络活动来控制程序的执行另外所有的路由和地址解析问题都在内核中实现

Linux用户空间和内核空间 用户态和内核态(扬智电子简答)

用户空间(用户态):用户程序的运行空间为了安全它们是隔离的即使用户的程序崩溃内核也不会受到影响只能执行简单的运算不能直接调用系统资源必须通过系统接口system call),才能向内核发出指令内核空间(内核态):Linux内核的运行空间可以执行任意命令调用系统的一切资源

Linux用户态和内核态切换三种方式(扬智电子简答延伸)

1 系统调用这是用户态进程主动要求切换到内核态的一种方式用户态进程通过系统调用申请使用操作系统提供的服务程序完成工作例如fork()就是执行了一个创建新进程的系统调用系统调用的机制和新是使用了操作系统为用户特别开放的一个中断来实现所以系统调用本身就是中断但是软件中断跟硬中断不同2 异常如果当前进程运行在用户态如果这个时候发生了异常事件就会触发切换例如缺页异常3 外设中断当外设完成用户的请求时会向CPU发送中断信号这时CPU会暂停执行下一条即将要执行的指令而转到与中断信号对应的处理程序去执行如果前面执行的指令时用户态下的程序那么转换的过程自然就会是 由用户态到内核态的切换如硬盘读写操作完成系统会切换到硬盘读写的中断处理程序中执行后边的操作等实际上最终是中断机制实现的

Linux系统中资源分配、资源调度的最小单位(移远通信面试)

1 进程是操作系统分配资源的最小单位
  资源调度的最小单位是进程

2 线程是操作系统调度的最小单位
  CPU调度的最小单位是线程

进程与线程的区别(模拟面试、扬智科技面试)

1 根本区别进程是操作系统资源分配的基本单位而线程是处理器任务调度和执行的基本单位2 资源开销每个进程都有独立的代码和数据空间程序上下文),程序之间的切换会有较大的开销线程可以看做轻量级的进程同一类线程共享代码和数据空间每个线程都有自己独立的运行栈和程序计数器PC),线程之间切换的开销小3 包含关系如果一个进程内有多个线程则执行过程不是一条线的而是多条线线程共同完成的线程是进程的一部分所以线程也被称为轻权进程或者轻量级进程4 内存分配同一进程的线程共享本进程的地址空间和资源而进程之间的地址空间和资源是相互独立的5 影响关系一个进程崩溃后在保护模式下不会对其他进程产生影响但是一个线程崩溃整个进程都死掉所以多进程要比多线程健壮6 执行过程每个独立的进程有程序运行的入口顺序执行序列和程序出口但是线程不能独立执行必须依存在应用程序中由应用程序提供多个线程执行控制两者均可并发执行

进程的相关函数的函数名(移远通信面试延伸、扬智科技面试延伸)

进程的创建 fork()/vfork() 
进程的退出 exit(int status)/_exit(int status)
进程的等待回收 wait(int *stat_loc)/waitpid(pid_t pid, int *stat_loc, int options)
获取进程的id以及获取父进程的ID getpid(void)/getppid(void)
获取当前进程所在进程组的ID getpgrp(void)
创建或加入其他进程组 setpgid(pid_t pid, pid_t pgid)

进程——虚拟(以及对应知识)(扬智科技面试)

概念物理层面上只有一个CPU但是我们要让每一个进程都认为自己在使用CPU都认为自己拥有整个内存空间这就是进程的虚拟化通过地址空间实现过程进程从硬盘加载到内存操作系统为其创建task_struct(进程控制块)和mm_struct(虚拟地址)并且用指针把二者关联起来然后虚拟地址通过页表和物理内存建立关系地址空间本质上是描述进程所占有空间的一张表存在于操作系统内核中是一种数据结构该数据结构把内存分成若干个区域每一个进程都有一个地址空间虚拟地址空间中该虚拟地址空间暴露给上层的地址叫做虚拟地址在进程运行时通过页表映射转换到实际内存中然后得到对应的代码和数据

image-20230530115007245

设计出虚拟地址和物理地址的好处(扬智科技面试延伸)

1 既然每个进程的内存空间都是一致而且固定的所以链接器在链接可执行文件时可以设定内存地址而不用去管这些数据最终实际的内存地址这是有独立内存空间的好处2 当不同的进程使用同样的代码时比如库文件中的代码物理内存中可以只存储一份这样的代码不同的进程只需要把自己的虚拟内存映射过去就可以了节省内存3 在程序需要分配连续的内存空间的时候只需要在虚拟内存空间分配连续空间而不需要实际物理内存的连续空间可以利用碎片

Linux中进程调度的方法(移远通信面试)

1 SCHED_OTHER 	分时调度策略。(非实时调度策略)
2 SCHED_FIFO 	实时调度策略先到先服务一直运行到有更高优先级的任					务或者自己放弃若遇到相同优先级的任务则要等进程运					行完毕或者主动放弃才会运行另一个相同优先级的任务3 SCHED_RR 		实时调度策略时间片轮转给进程分配时间片每个进程					运行完对应的时间片后系统重新分配时间片若同时有实时调度策略和分时调度策略实时调度策略的进程准备好后会立即抢占非实时的进程

进程有哪几种状态

1 就绪态进程已经运行了但是还没有获取cpu的使用权当cpu的调度算法切换到该进程那么进程就能转入到执行态2 执行态进程已经运行并且cpu的使用权也获取了3 睡眠态使用了sleep()等等带有阻塞功能的函数(pause()、wait()、waitpid()),进程都会进入睡眠态4 暂停态进程收到暂停信号5 僵尸态进程退出了没有回收就变成僵尸态6 死亡态进程退出了有回收

Linux中子进程从父进程继承了什么

1 用户ID号和用户组号
2 环境变量
3 堆栈
4 共享内存
5 打开文件的描述符
6 执行时的关闭标志
7 信号控制设定(Signal)
8 进程组号
9 当前工作目录
10 根目录
11 文件方式创建屏蔽字
12 资源限制
13 控制终端

Linux中子进程创建后独有的属性(牛客)

1 进程号
2 属于子进程的父进程的进程号
3 自己的文件描述符和目录流的拷贝
4 子进程的进程正文数据和其他锁定内存
5 异步输入和输出
(一般来说回答文件锁和进程号即可)

system和exec函数族(模拟面试延伸)

作用实现在一个进程中调用执行另外一个进程

用法1 system用法,函数system()
2 exec用法各种exec族的函数常用execl()(例子execl("/bin/ls","ls","-l",NULL);该代码功能和shell中的"ls -l"功能一样)

system和exec函数族区别执行完exec函数之后它会取代原调用进程的数据段代码段和堆栈段在执行完之后原调用进程的内容除了进程号外其他全部都被替换了看到的现象就是exec函数后面的代码没有办法执行了(因为被取代了);system则是执行完以后后面的代码也能够正常执行

共享内存(模拟面试延伸)

原理多个进程申请同一块内存区域用于通信

使用共享内存出现的问题创建失败文件已经存在
原因共享内存创建过一次下次就不能重复创建了
解决方法1 不靠谱的方法手动删除下次还要手动删除
2 判断共享内存创建失败的原因如果是由于已经存在我就直接打开共享内存不新建了使用errno判断   

使用1 申请共享内存使用shmget()函数申请共享内存
2 映射得到共享内存的首地址使用shmat()函数
3 使用完后解除映射使用shmdt()函数
4 删除共享内存设置/获得共享内存的属性使用shmctl()函数

信号量(模拟面试)

作用协调多个进程对于共享资源(临界区资源)的访问进程1在访问共享资源的时候其它进程不允许访问确保任意时刻只有一个进程在访问共享资源确保某个进程在某个时刻对于共享资源具有独占性

使用1 申请信号量semget()函数申请信号量
2 对信号量进行P操作和V操作即对信号量进行加减我们是对Linux内核中自带的结构体struct sembuf中的成员sem_op赋予正负值来进行PV操作        
										加法操作(V操作) --把信号量增加
										减法操作(P操作) --把信号量减少
3 使用semctl()函数对想要所用的信号量进行赋值初始化获取信号量删除信号量这几种操作特点1 信号量的值不能为负数
2 信号量的值如果变成0你还要进行p操作会阻塞当前进程

消息队列(模拟面试)

特点1 生命周期随内核消息队列会一直存在需要我们使用接口函数删除或者使用命令删除2 消息队列可以双向通信(通信双方可以选择性的接收信息通过所谓的消息类型去区分不同的消息)
3 克服了管道只能承载无格式字节流的缺点
4 如果接收的消息类型不存在会阻塞
5 如果消息队列中有多条类型一样的消息接收的时候只能按照发送的先后顺序接收(队列的特点)

不足每个消息有一个最大的长度即有长度上限

使用1 申请消息队列使用msgget()函数申请消息队列
2 使用消息队列收发信息使用函数msgsnd()函数需要将发送的信息打包成结构体结构体内包含消息的类型和真实的信息随后才可收发信息
3 删除消息队列设置获取消息队列的属性使用msgctl()函数通过消息队列的ID号进行对应的删除等操作

管道(模拟面试延伸)

无名管道:(int pipe(int fildes[2]);读是fildes[0],写是fildes[1])
创建时会得到分别用来进行读取数据和写入数据的文件描述符
特点1 无名管道有固定的读写端不能弄错
2 如果无名管道没有进程写入数据那么read读取管道信息会阻塞
3 只能用于具有父子兄弟关系的进程之间通信

有名管道:(int mkfifo(const char *pathname, mode_t mode);)
会得到一个管道文件用来进行进程之间的通信和无名管道一样使用系统IO的函数openreadwrite等特点1 有名管道没有固定的读写端
2 如果有名管道没有进程写入数据那么read读取管道信息会阻塞
3 有名管道的适用范围更广既能用于父子兄弟进程之间通信也能用于没有任何血缘关系进程间通信
4 有名管道只能在纯粹的linux环境中创建

不足有名管道只用于通信不保存数据(例如进程1写入内容到管道中然后退出运行进程2读取内容是读取不了的)

使用有名管道出现的问题创建有名管道失败!
报错为File exists
原因上一次运行程序已经创建过一个管道文件不能重复创建
解决方法判断管道文件是否存在存在我就直接打开不存在我就创建然后打开

信号(模拟面试延伸)

Linux中定义了62个信号从1号到64号其中32号和33号没有定义1到31号是一组名为非实时信号可以嵌套响应(进程在响应A信号的时候B信号发送过来进程会立马响应B信号B信号响应完了在回到A信号继续响应)。
34到64好是另外一组叫做实时信号不可以嵌套响应重要编号2 	SIGINT		等于Linux中的ctrl+c
18	SIGCONT	让进程继续执行
19	SIGSTOP	让进程暂停执行

linux中信号四种响应方式
1信号的默认动作响应linux已经规定好了所有信号的默认动作绝大部分默认动作都是终止进程
2 改变信号的响应动作signal/sigaction函数去捕捉信号并改变注意有两个信号SIGKILL和SIGSTOP很特殊不能改变它们的默认动作
3 忽略信号(signal(信号,SIG_IGN);)左耳进右耳出当信号发送过来的时候进程当它不存在直接舍弃该信号(不存在了)。
注意有两个信号SIGKILL和SIGSTOP很特殊不能忽略4 信号的阻塞(信号的屏蔽定义阻塞掩码集将信号加入进去即可阻塞信号),阻塞信号仅仅只是把信号挡在进程的外面(暂时挂起),不去响应等到解除阻塞依然能够正常响应信号(信号依然存在)。
注意有两个信号SIGKILL和SIGSTOP很特殊不能阻塞

多个进程同时打开同一个文件(扬智科技面试)

1 任何一个进程删除该文件时另外一个进程会立即出现读写失败2 有缓冲的情况下一个进程对文件长度和内容进行修改另外一个进程可以立即感知3 多个进程中分别产生生成多个独立的fd4 多个进程可以分别读取文件的不同部分而不会相互影响

野指针的危害(海康威视面试)

1指向不可访问的地址
危害触发段错误2指向一个可用的但是没有明确意义的空间
危害程序可以正确运行但通常这种情况下我们就会认为我们的程序是正确的没有问题的然而事实上就是有问题存在所以这样就掩盖了我们程序上的错误3指向一个可用的但是正在被使用的空间
危害如果我们对这样一个指针进行解引用对其所指向的空间内容进行了修改但是实际上这块空间正在被使用那么这个时候变量的内容突然被改变当然就会对程序的运行产生影响因为我们所使用的变量已经不是我们所想要使用的那个值了通常这样的程序都会崩溃或者数据被损坏

简述i++和++i(模拟面试+延伸)

i++是先使用i的值再i+1
++i是先i+1再使用i的值

底层原理1 i++++i都是带有返回值的函数
2 i++返回的是一个常量值
3 ++i返回的是i的引用/指针

例子若i=1(++i)+(++i)的值为6因为第一个++i时i变为2第二个++i时i变成3则最终为3+3得6

sizeof和strlen区别(模拟面试)

sizeof是一个运算符能够计算出变量的字节大小对于字符串来说sizeof会把字符串最后的那个'\0'字节也计算进去strlen是C语言库里提供的一个计算字符串长度的函数遇到'\0'就会结束所以并不是适用于所有的情况

new/malloc delete/free的区别(模拟面试延伸)

1 new从自由存储区上分配内存malloc从堆上分配内存。(自由存储区是堆与静态存储区)
2 newdelete返回的是对应的数据类型指针malloc和free返回的是void*类型3 使用new申请内存时无须指定申请的内存块的大小malloc则必须指出所需内存的尺寸4 new可以调用对象的构造函数delete可以调用析构函数而malloc和free仅只能分配内存和回收内存5 newdelete是运算符(操作符),mallocfree是函数

内存泄漏和堆内碎块(模拟面试、海康威视面试)

内存泄漏一直申请堆空间但没有释放导致堆内存越来越少最后没有可以使用的内存堆内碎块频繁地分配和释放不同大小的堆空间会导致堆内碎块预防内存泄漏1 养成良好的代码习惯保证malloc/new和free/delete匹配2 有专门的判断代码中有无内存泄漏情况的软件预防堆内碎块1 在进程启动时使用 int mallopt(int paramint value) 函数显式地设置 M_MMAP_THRESHOLD 的值为128K关闭M_MMAP_THRESHOLD动态调整特性
2 优化应用程序中内存管理方式不要频繁申请释放内存空间减少内存碎片

volatile关键字(移远通信面试)

作用修饰易变的变量告诉编译器这个变量的值短时间内会改变很多次不要去优化该变量系统每次使用这个被修饰的变量时都是直接从对应的内存当中提取而不会利用存在cache当中的原有数值以适应它未知何时会发生的变化系统对这种变量的处理不会做优化例如1 并行设备的硬件寄存器
2 一个中断服务子程序中会访问到的非自动变量
3 多线程应用最后那个被几个任务共享的变量

static关键字(纳思达面试、移远通信面试)

C语言中1 修饰局部变量
2 修饰全局变量
3 修饰函数

C++1 修饰类中的方法
2 修饰类中的属性

const关键字(纳思达面试)

1 修饰普通变量让变量的读写属性变为只读即常说的常量不能修改可以访问2 修饰指针
	(1)指针常量int *const p;不能修改p的指向可以修改*p的值。
	(2)常量指针int const *p;不能修改*p的值可以修改p的指向3 C++中修饰类的成员函数表示该函数只能对类中的成员属性进行读操作不能改变类中的成员属性

一个参数既可以被const修饰也能被volatile修饰吗?

可以volatile修饰是因为它可能被意想不到的改变const修饰是因为程序不应该试图去修改它。(例子只读的状态寄存器)

内联函数inline(模拟面试)

1.什么是内联函数
     关键字inline
          inline 函数的返回值  函数名(形参)
          {}
2.内联函数的作用
   解决函数调用时入栈和出栈的时间耗费对于经常要使用的短小的代码适合定义成内联函数

内联函数的原理编译器会在调用的位置直接把内联函数的源码复制过来

优点节约了函数调用入栈出栈的时间耗费内联函数用内联代码替换函数调用
内联函数体的代码不能过长因为内联函数省去调用函数的时间是以代码膨胀为代价的内联函数不能包含循环语句因为执行循环语句要比调用函数的开销大缺点增加主程序的长度增加了主函数占用的内存耗费了比较多的内存  
    
3.什么时候使用内联函数
  函数代码量很小并且需要反复使用 --定义成内联  

C语言中EOF的值是多少?(扬智科技面试)

-1

C语言与C++中NULL的值是多少?(通则康威简答延伸)

C语言中空指针是NULL但并没有规定NULL必须是0但是C++中空指针必须是0值原因C++为了支持模版泛型编程强行规定了所有类型都必须有一个0值而指针0值就是空指针此时访问NULL就等于访问0地址C语言没有这样规定所以可以使用任意值表示NULL但一般情况下NULL在实际底层调用时就是0所以也可以看作NULL和0的值都是一样的

递归次数过多如何优化

1用循环进行替换(非递归方法实现)
2限制递归次数
3若必须要递归又不允许限制递归次数则使用异步任务队列”。这样就可以达到将递归函数从执行栈中转移到异步队列中从而减轻执行栈压力的目的

面向对象编程的三个性质(模拟面试)

1 封装
	一个对象封装自己的属性和方法
	优点1良好的封装可以减少耦合
	2类内部的结构可以自由修改
	3可以对成员进行更精确的控制
	4隐藏信息实现细节
2 继承
	使用已存在的类作为基础建立新的类新的类可以增加新的数据或者功能也可以使用父类的功能但不能选择性继承父类
	缺点1父类改变子类就会跟着改变
	2继承破坏了封装
	3继承是一种强耦合关系
3 多态
	一个引用变量倒底会指向哪个类的实例对象该引用变量发出的方法调用到底是哪个类中实现的方法必须在由程序运行期间才能决定
	优点不修改程序代码就可以改变程序运行时所绑定的具体代码让程序可以选择多个运行状态这就是多态性

C++中的多态(模拟面试)

C++具有继承关系的类中它们都具有相同名字的方法这种情况就是多态分类编译时多态函数重载
运行时多态父类的指针引用指向不同的子类对象  

虚函数就是为了多态而产生的多态的特点和要求
1 必须要有继承没有继承就没有多态
2 子类必须要重写父类的同名方法
3 父类的同名方法必须定义成虚函数
注意父类的同名方法定义成了虚函数所有子类中同名的方法全部都默认是虚函数(子类加不加virtual都行)

底层原理1 虚函数表(虚表):C++中专门用来存放虚函数地址的一种数据结构(本质是个存放函数地址的数组)。
2 一个类中定义了虚函数那么这个类以及它派生出来的子类都会有各自独立的虚函数表该类所有的对象中会新增一个指针该指针用来指向虚表的首地址父类的指针或者父类的引用去调用方法的时候其实就是去查询虚函数表

C++中必须用到this指针的情况

1 函数的返回值是该类对象自身的时候如下例Cat &cmpAge(Cat &other)
                   {if(other.age>age) return other;
                    else return *this;}
2 类中方法用到了对象自身的情况

C++虚继承(模拟面试及延伸)

普通继承跟虚继承的区别
第一虚继承可以解决二义性和A被构建多次这两个问题普通继承不能解决第二只要一个类虚继承了其它类那么该类所有的对象中都会新增一个指针该指针专门用来指向系统中虚基类表的首地址虚基类表C++中专门用来存放虚基类地址的一种数据结构什么时候用: 环状继承除了头尾中间层使用虚基类若不用则会导致二义性(即环装继承中最后一个子类调用最原始的父类的函数时无法确认最后一个子类调用了哪一个第二级的父类中最原始父类的副本中的函数)和A被构建多次

C++类内static静态成员变量(纳思达面试)

在C++类的静态成员static member必须在类内声明在类外初始化像下面这样class A
{  
    private:
    static int count ; // 类内声明
};
int A::count = 0 ; // 类外初始化,不必再加static关键字
因为静态成员属于整个类而不属于某个对象如果在类内初始化会导致每个对象都包含该静态成员这是矛盾的能在类中初始化的成员只有一种那就是静态常量成员此外还需要注意的是声明和定义的区别:
①变量定义用于为变量分配存储空间还可为变量指定初始值程序中变量有且仅有一个定义。
②变量声明用于向程序表明变量的类型和名字在该题目中的定义指的是分配空间

指针和引用的区别(纳思达面试)

1 初始化:引用在定义时必须初始化,指针则没有要求(尽量初始化,防止野指针)
2 引用在初始化引用一个实体后,就不能再引用其它实体,而指针可以在任意时候指向一个同类型实体
3 没有NULL引用,但是有nullptr指针
4 在sizeof中含义不同: 引用结果为引用类型的大小,但指针始终是地址空间,所占字节个数(32位平台占4个字节)
5 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
6 有多级指针,但没有多级引用
7 访问实体的方式不同,指针需要显式解引用,引用编译器自己处理
8 引用比指针使用起来相对安全

堆和栈的区别(纳思达面试)

1 管理方式不同栈由操作系统自动分配释放无需我们手动控制堆的申请和释放工作由程序员控制容易产生内存泄漏2 空间大小不同每个进程拥有的栈的大小要远远小于堆的大小3 生长方向不同堆的生长方向向上内存地址由低到高栈的生长方向向下内存地址由高到低4 分配方式不同堆都是动态分配的没有静态分配的堆栈静态分配是由操作系统完成的比如局部变量而动态分配是由操作系统进行释放无需我们手动释放5 分配效率不同栈由操作系统自动分配有专门的指令执行效率比较高堆则是由库函数或者运算符申请机制比较复杂效率比栈低得多6 存放内容不同栈存放的内容是函数返回地址相关参数局部变量和寄存器内容等堆中具体存放内容是由程序员来填充的

scanf的原理(模拟面试)

缓冲区:计算机内存中一块特殊的区域这个区域专门留给scanf/printf来使用

底层原理:用户从键盘输入的任何数据都会被当成字符串存放到系统的IO缓冲区里面

scanf依据程序员写的格式控制符从IO缓冲区里面读取合适的字符串然后把这个字符串转换成你需要的数据类型

问题scanf读取数据如果用户不配合输入的数据类型不正确该怎么办解决方法scanf的返回值表示用户从键盘输入的符合要求的数据类型个数

printf的原理(模拟面试延伸)

底层原理打印的数据先存放到IO缓冲区

代码中遇到如下几种情况会自动刷新缓冲区(所谓的自动刷新缓冲区就是把缓冲区里面的内容在屏幕上显示出来)
情况1return/exit/程序结束  
情况2缓冲区满了就会自动把缓冲区里面的内容刷新到液晶屏上显示出来
情况3回车

怎样检测链表中存在循环(各种笔试里见过好几次)

1 修改链表的数据域向里面增加一个标记位遍历链表每次遍历到未遍历过的节点则将节点的标记位修改若出现了标记位是修改过的值的节点则证明链表存在循环2 若链表是只读的不能修改数据域则建立一个数组访问每一个元素并将元素存入链表中然后检查下一个节点拿它的数据和数组中的数据进行遍历比较若出现在数组中则存在循环3 内存容量有限不能使用数组假定环出现在前N个节点处则建立一个指针指向头结点的下一个结点随后遍历链表和建立的指针比较若无相同则建立的指针指向下一个结点继续遍历链表与其比较直到出现有相同的节点则证明有循环若新建指针已经到达第N个节点则无循环4 内存容量有限不能使用数组并且循环可能出现在链表任何一处则我们先排除链表只有三个指针的情况随后建立两个指针P1P2P1指向头结点的下一个节点(第二个节点),P2指向头结点下一个节点的下一个节点(第三个节点),然后我们每一次令P1向后指向一个节点P2每次向后指向两个节点进行循环若最终P1P2都指向NULL则没有循环若最终出现P1和P2指向同一个节点则证明存在循环

动态库静态库编译

动态库后缀名是.so结尾
静态库后缀名是.a结尾
     
动态库特点/问题1 使用动态库编译程序动态库的源码不会被编译到程序中需要等到程序运行的时候才去库文件中加载源码
2 只要你使用动态库去编译程序运行程序的时候都会去系统的环境变量中去寻找动态库文件找不到就报错

静态库特点/问题1 你使用静态库编译静态库中的源码会被一起编译到程序中运行程序的时候不需要依赖静态库
2 静态库编译的程序占用的存储空间要比动态库编译的大

对比动态库和静态库结论1动态库编译的程序占用的存储空间要比静态库编译的小  
原因动态库编译程序动态库里面的源码没有编译到程序里面的
      静态库编译程序静态库里面的源码需要编译到程序里面的

结论2如果动态库和静态库放在一起编译器优先使用谁??      
        优先使用动态库编译

程序编译的四个过程

第一步预处理(处理C程序中所有#开头的语句)
        	#开头的语句展开gcc hello.c  -o hello.i  -E  
			(-E 编译选项用来对程序进行预处理)
第二步编译(.i文件编译得到.s的汇编文件)
			gcc hello.i  -o hello.s  -S  
第三步汇编(.o文件叫做可重定位文件)
			gcc hello.s  -o hello.o  -c
第四步链接生成最终的可执行程序
			gcc hello.o -o hello

什么叫模块化,设计一个系统时是否分的模块越多越好(格力笔试)

模块化就是程序划分成可独立命名且独立访问的模块每个模块完成一个子功能把这些模块集成起来构成一个整体可以完成指定的功能满足用户的需求不一定越多越好当模块数目增加时每个模块的规模将减小开发单个模块需要的成本确实减少了但是随着模块数量增加设计模块之间连接所需要的工作量也将增加所以设计一个系统时并不一定模块越多越好

SPI协议(CVTE一面)

首先SPI其实是串行外设接口的缩写是一种全双工同步的通信总线并且只占用了芯片的四根线节约了芯片的管脚具有简单易用的特性是一种高速高效率的串行接口技术SPI四条逻辑线1 MISO	主机输入从机输出(数据来自从机)
			      2 MOSI 	主机输出从机输入(数据来自主机)
			      3 SCLK 	串行时钟信号由主机发送给从机
			      4 NSS 	片选信号由主机发送以控制与哪个从机通信通常是低电平有效
SPI的优点1 全双工串行通信2 高速数据传输速率3 简单的软件配置4 极其灵活的数据传输不限于8位它可以是任意大小的字5 非常简单的硬件结构从站不需要唯一地址(与I2C不同)。从机使用主机时钟不需要精密时钟振荡器/晶振(与UART不同)。不需要收发器(与CAN不同)。

SPI的缺点1 没有硬件从机应答信号主机可能在不知情的情况下无处发送);
2 通常仅支持一个主设备3 需要更多的引脚与I2C不同);
4 没有定义硬件级别的错误检查协议5 与RS-232和CAN总线相比只能支持非常短的距离(1到3米);
SPI使用时的通信模式多NSS(和对应的从机通信时响应的NSS为低电平其他的NSS为高电平若出现多个从机的NSS同时为低电平则可能他们都试图从一条MISO线上传输数据最后导致接收的数据为乱码)

image-20230530120435321

菊花链(数据信号以串行的方式从一个设备依次传入下一个设备不断循环直到数据到达目标设备缺点是若某一设备出现问题那么比它优先级低的设备就接收不到数据了离主机距离越远优先级越低)

image-20230530120450299

SPI总线有四种模式分别是由时钟极性CKP和时钟相位CKE配合而来1 时钟极性CKP = 0时钟相位CKE = 0
2 时钟极性CKP = 0时钟相位CKE = 1
3 时钟极性CKP = 1时钟相位CKE = 0
4 时钟极性CKP = 1时钟相位CKE = 1
(时钟极性CKP = 0空闲状态为低电平CKP = 1空闲状态为高电平)
(时钟相位CKE = 0从第一个时钟边沿开始传输数据CKE = 1从第二个时钟边沿开始传输数据)

RS-232(SCI串行通信接口的一种)(都是串口通信)(CVTE一面延伸)

定义RS-232是常用的串口通信接口标准之一。(全双工通讯方式)

RS-232接口一般是9针的其中分别为RXD,TXD,GND,DCD,DTR,DSR,RTS,CTS,RI各针位功能DCD-载波检测通知给DTERXD-接收数据TXD-发送数据GND-0电平位DTR-DTE告诉DCE准备就绪DSR-DCE告诉DTE准备就绪RTS-请求发送(DTE向DCE发送数据请求),CTS-清除发送(DCE通知DTE可以传数据),RI-振铃指示(DCE通知DTE有振铃信号)

其中DTR,DSR,RTS,CTS用于硬件流控硬件连接的方式分为9线连接5线连接和3线连接一般只使用3线连接(RXD,TXD,GND),无法实现硬件流控功能即大量的数据传输若要实现大量数据传输要使用5线或者9线连接特点(优点):
1 RS-232的电气逻辑标准(TTL)是负逻辑+3V到+15V为逻辑"0",-3V到-15V为逻辑"1",-3V到+3V为非法状态。
2 信号线少RS-232规定了25条信号线而在一般应用中使用3条到9条信号线就可实现全双工通信使用RXDTXDGND三线即可实现简单的全双工通信3 灵活的波特率选择可以根据不同设备的传送速率来选择对应的波特率对于慢速外设可以选择较低的传送速率反之也可4 理论上传送距离较远RS-232采用普通的串行传送方式的话传送距离一般为30米还可搭配其他外设达到更远的传送距离例如光纤等缺点1 接口的信号电平较高容易损坏接口电路的芯片又因为它是负逻辑想要与常规TTL电路连接的话需要使用电平转换电路2 传输速率较低异步传输时波特率为20Kbps在CPLD开发板中综合程序波特率只能选192003 接口使用一根信号线和一根信号返回线(RXD和TXD)构成共地的传输方式这种共地传输容易产生共模干扰抗噪声干扰性弱4 传输距离有限实际使用时只能在15米左右三种通讯方式1 两设备直接通过RS-232标准通讯发出TTL电平通过电平转换芯片转换成232所用的电平2 USB转串口和电脑进行通讯使用CH340电平转换芯片并且电脑安装CH340驱动3 直接通过TTL电平进行通讯一般用于与带串口的设备或者传感器通讯不需要通过电平转换芯片例如和GPS模块串口转WIFI模块HC04蓝牙模块等通讯工业通信中一般使用RS-485因为RS-485是差分信号可以抑制共模干扰因此在恶劣的环境中拥有很好的抗干扰性比较稳定

UART(SCI和UART就是的士和出租车的区别)(CVTE一面延伸)

定义通用异步收发传输器

发送端的UART将来自控制设备(例如CPU)的并行数据转换为串行数据以串行方式将其发送到接收端的UART然后由接收端的UART将串行数据转换成并行数据以用于接收设备的正常处理UART的数据传输只需要两条线分别是RX和TXTX为发送端RX为接收端TTL输入高电平最小为2V输出高电平最小为2.4V典型值是3.4V输入低电平最大为0.8V输出低电平最大为0.4V典型值为0.2V优点1 通信只需要两条数据线2 无需时钟信号3 有奇偶校验位方便通信的差错检查4 只需要接收端和发送端设置好数据包结构即可稳定通信缺点1 数据帧最大只能支持9位的数据2 不支持多主机或者多从机的主从系统现今通常使用外部USB转UART转换器例如CH340驱动现在很多处理器和芯片都内置了UART

CAN(CVTE一面延伸)

通讯方式异步通讯即半双工(无法同时接收与发送同一时刻接收与发送只能实现一个)

组成由CAN_HIGH和CAN_LOW两条信号线组成。(没有时钟信号线)
又由这两条信号线可以组成两种网络1 闭环总线网络特点高速短距离闭环最高速度为1Mbps最长距离40m2 开环总线网络特点传输距离远开环最高速度为125Kbps最远距离1km通讯节点CAN协议可以挂载多个节点通过总线来实现节点通讯可以对节点的数据内容进行编码理论上节点个数不受限制通讯节点构成由一个CAN控制器和一个CAN收发器组成通讯节点收发信号1 发送数据控制器发送一个信号(0或1),收发器将这个信号变成差分信号传送到总线中2 接收数据收发器将差分信号转化为0或1的二进制编码波特率要求由于CAN协议没有时钟信号线各个节点要用相同特定的波特率进行通讯

image-20230530120613054

Linux内核中提供了API给程序员使用CAN协议STM32上也有对应的外设提供了相应的库函数给程序员使用在CAN总线接口协议中错误状态可分为三种主动错误被动错误和总线关闭1 主动错误状态是可以正常参加总线通信的状态
2 处于被动错误状态是可以正常参加总线通信的状态处于被动错误状态的单元即使检测出错误而其他处于主动错误状态的单元如果没发现错误整个总线也被认为是没有错误的3 总线关闭态是不可以参加总线上通信的状态信息的接收和发送均被禁止

IIC/I2C(资芯电子笔面)

IIC通信由两根线构成分别是1 信号线(SDA)
									2 时钟线(SCL)
优点/作用1 简化了硬件电路PCB的布线降低了系统成本提高了系统可靠性。(为什么因为IIC总线只需要两根线总线接口集成在了芯片内部不需要特殊的接口电路芯片内除了这两根线和少量的中断线没有其他的线用户IC可以很容易形成标准化和规模化便于重复利用。)
2 数据传输和地址设定由软件来决定与设定非常灵活总线上器件的增加和删除不影响其他器件的正常工作3 IIC总线可通过外部连线进行在线检测便于系统故障诊断和调试故障可立即被寻址4 连接到相同总线上的IC数量只受总线最大电容的限制5 总线具有极低的电流消耗抗高噪声干扰缺点1 传输速率慢2 IIC是半双工通信在同一时间只能进行接收数据或者发送数据IIC协议层开始信号SCL为高电平时SDA由高电平向低电平跳变开始传送数据结束信号SCL为高电平时SDA由低电平向高电平跳变结束传送数据应答信号接收数据的IC在接受到8bit数据后向发送数据的IC发出特定的低电平脉冲表示已收到数据CPU向受控单元发出一个信号后等待受控单元发出一个应答信号CPU接到应答信号后根据实际情况作出是否继续传递信号的判断若未收到应答信号则判断为受控单元出现故障

USB协议(CVTE一面延伸)

目前常用的USB版本USB2.0和USB3.0
USB 2.0 传输速率480Mbps(60MB/s)
USB 3.0 传输速率 5Gbps(500MB/s)

USB2.0使用4芯的屏蔽线一对差分线(D+,D-)传输信号另一对(VCC和GND)传输5V的直流电USB3.0设计了9条内部线路其中继承了USB2.0的D+D-VCC和GND还有一对为USB3.0专门设计的线路SSRX和SSTX分别为SSRX+,SSRX-,SSTX+,SSTX-以及一条GND_GRAIT线USB设备分为三层1 最底层总线接口用于发送和接收数据包2 中间层处理总线接口和不同的端点之间的数据流3 最上层USB设备提供的功能USB的传输方式1 批量传输用在需要大量传输数据但对实时性要求不高的情况下。(U盘)
2 中断传输中断传输的数据量很小一般用于通知Host某个事件的来临。(USB鼠标键盘等)这里的中断不是硬件上的中断而是USB主机按照指定的时间不断查询设备是否有数据传输3 同步传输要保证信息传输的同步性(摄像头)。特点虽然要求实时性但不要求百分百的正确4 控制传输负责向USB设置一些控制信息一个USB控制器下面挂接很多设备要怎么传输数据还有寻址等都是通过控制传输建立起来的USB主机和从机之间的通信通过管道来实现任何一个USB设备上电后就会存在一个管道USB主机通过管道来获取从机的描述符配置等信息在主极端管道骑士就是一组缓冲区用来存放主机数据在设备端管道对应一个特定的端点端点作用主机通过端点与设备进行通讯以使用设备的功能定义端点实际上就是一个一定大小的数据缓冲区特点1 每个端点都有一定的特性包括传输方式总线访问频率带宽端点号数据包最大容量等2 端点必须在设备配置后才能生效(端点0除外它是用来初始化设备的)。

管道定义一个USB管道是驱动程序的一个数据缓冲区与一个外设端点的连接代表了两者之间传输数据的能力(只是一个逻辑上的概念不是真实存在的)。
分类1 数据流管道(其中的数据没有USB定义的结构);
		2 消息管道(其中的数据必须有USB定义的结构);
特点1 所有设备必须支持端点0作为设备的控制管道2 通过控制管道可以获取完全描述USB设备的信息

看门狗watch dog(资芯电子笔面)

作用防止程序无限制的执行造成死循环可以用在接收和发送数据时对接收和发送超时进行处理起到数据保护和保护电路的作用原理本质上是一个定时器电路系统正常运行时需要在一定时间间隔内对看门狗计数器清零即喂狗不让复位信号产生一旦出现问题没有执行喂狗”,系统将会被复位种类1 CPU内部自带的看门狗
		2 独立的看门狗芯片

使用方法在程序中隔一段时间执行一次喂狗操作即在一个完整的程序段中间隔性放入多个喂狗操作。(放入主程序中或者放在中断子程序中)

什么时候会失效1 系统内部定时器自身发生故障看门狗就会失效
2 中断系统故障导致定时器中断失效
3 整个程序死机主程序出现异常

RAM与ROM的区别(CVTE一面延伸)

RAM随机存取存储器是与CPU直接交换数据的内部存储器用于存放各种现场的输入/输出数据或者当作堆栈使用。(例如运行内存)
ROM只读存储器事先写好的整机工作过程中只能读出不能加以改写。(例如存储系统相关的信息和BIOS等)

区别RAM在断电后保存在上面的数据会消失而在ROM上的数据不会自动消失可以长时间断电保存

比特率定义

一秒钟内在通信网络上传输的比特数就是比特率

51单片机中,可拓展的外部程序储存器最大为多少字节

分两种情况:(16位寻址故最多为2^16 = 64KB)
1 EA接高电平单片机先从内部读取程序超出部分从外部读取故外部可拓展60K字节。(内部4K外部60K)
2 EA接低电平单片机直接从外部读取程序故可拓展64K字节

单片机使用过程中,堆栈的作用(资芯电子笔面延伸)

1 子程序调用和中断服务时CPU自动将当前PC值压栈保存返回时自动将PC值弹栈2 保护现场/恢复现场3 数据传输

单片机的IO口配置有哪些(资芯电子笔面延伸)

1 准双向口配置
2 开漏输出配置
3 推挽输出配置
4 高阻配置

中断的功能(资芯电子笔面延伸)

1 实时处理功能实时控制中现场各种外界变量变化这些变量可根据要求随时向CPU发出中断申请请求CPU及时处理中断请求2 故障处理功能针对难以预料的故障如掉电等可通过中断系统由故障源向CPU发出中断请求再由CPU转到对应的故障处理程序进行处理3 分时操作使CPU与外设同时工作CPU在启动外设工作后继续执行主程序同时外设也在工作每当外设做完一件事就发出中断申请请求CPU中断其正在执行的程序转去执行中断服务程序中断处理完后CPU恢复执行主程序外设继续工作这样CPU可启动多个外设同时工作大大提高效率

串口中断(CVTE一面延伸)

定义串口一旦接收到数据就会发生中断同时收到数据就会清除标识位(这是串口没有清除标识位也能正常工作的原因)

边沿触发中断和电平触发中断(CVTE一面)

边沿触发包括上升沿触发和下降沿触发边沿触发检测的是电平的变化高电平转化成低电平或者低电平转化成高电平时会触发
电平触发分为高电平触发和低电平触发边沿沿触发是锁存中断信号的由D触发器记忆若CPU来不及响应中断外部中断信号撤消后由于D触发器的记忆作用消失的中断信号仍然有效直到中断被响应并进入中断ISR记忆的中断信号才会由硬件自动清除电平触发根据硬件设计的不同分为即时触发和信号锁存触发1 即时的电平触发当外部中断信号撤消时中断申请信号随之消失如果在外部中断信号申请期间CPU来不及响应此中断那么有可能这次中断申请就漏掉了即时的电平触发是一个时间段需要一直触发中断的就用电平触发比如高电平触发只要检测到是高电平就触发中断2 信号锁存的电平触发当检测到高电平或低电平信号该触发信号也会被锁存类似于边沿触发但是触发信号需要进行手动清除

边沿触发及电平触发的区别
	如果是采用边沿检测外部中断检测到电平变化会中断但是如果中断检测口一直保持某一电平则无法产生下次中断需要等下次检测到电平变化才会中断中断标志在得到响应后由硬件自动清除如果是采用电平检测外部中断检测到低/高电平会中断但是如果中断检测口一直保持低电平中断处理完成后会继续产生下次中断需要检测到高电平才会停止中断产生中断标志在得到响应后由硬件手动清除

单片机的最小系统组成(资芯电子笔面)

1 电源部分(电源)
2 晶振部分(晶振)
3 复位部分(复位电路)

单片机中能够位寻址的寄存器的规律

寄存器的地址能够被8整除的就是可以位寻址的

单片机中上拉电阻和下拉电阻的作用

数字电路中只存在两种电平高电平和低电平在刚刚通电的时候电路中的这些状态是不确定的为了使电路确定状态必须使用上拉电阻和下拉电阻使一个不确定的电平变成高电平的是上拉电阻使一个不确定的电平变成低电平的是下拉电阻

单片机中IO口的作用

IO口最主要的功能用来与外部器件实现数据信息的交互速度匹配数据传送方式和增强单片机的负载能力

单片机的寻址方式

七种
1 立即寻址
2 直接寻址
3 寄存器寻址
4 寄存器间接寻址
5 相对寻址
6 变址寻址
7 位寻址

单片机的PC

定义单片机的PC是程序计数器一般用于存放将要执行的指令地址是一个16位的寄存器当执行一条指令时首先需要根据PC中存放的指令地址将指令取出送到指令寄存器中这个过程称为取指令”。于此同时PC中的地址自动加1跳转操作得到下一条指令的地址当前一条指令执行完毕CPU再根据PC取出下一条指令的地址并再得到下一条指令地址一次执行每一条指令

单片机的堆栈

定义在片内RAM中指定一个专门的区域来存放某些数据它遵循后进先出的原则这个RAM区叫堆栈。(通常是RAM区靠后的位置因为一般不安排在工作寄存器和可按位寻址的RAM区)

作用1 子程序调用和中断服务时CPU自动将当前PC值压栈保存返回自动将PC值弹栈2 保护现场/恢复现场
3 数据传输

DMA(优特科技笔试延伸)

DMA直接存储器访问

DMA传输数据从一个地址空间复制到另一个地址空间提供在外设和存储器之间或者存储器和存储器之间的高速数据传输(必须是高速不能是不同速度)。两种外设通过DMA快速传递数据不需要通过CPU节省了CPU的资源来做其他操作所需的核心参数1 数据的源地址(主要)
2 数据传输的目标地址(主要)
3 传递数据多少的数据传输量(主要)
4 进行多少次传输的传输模式

工作步骤及原理在实现DMA传输时由DMA控制器掌管总线因此存在一个总线控制权转移问题即DMA传输前CPU要把总线的控制权交给DMA控制器而在DMA传输后DMA控制器应立即把总线控制权再交回给CPU一个完整的DMA传输过程必须经过DMA请求DMA响应DMA传输DMA结束4个步骤DMA和CPU有三种方法分时使用内存1 停止CPU访问内存(在DMA传送过程中CPU基本处于不工作状态或者说保持状态)
2 周期挪用(当IO设备没有DMA请求时CPU按程序要求访问内存一旦有DMA请求则由IO设备挪用一个或几个内存周期)
3 DMA和CPU交替访问内存(当CPU工作周期比内存存取周期长很多此时采用交替访内的方法使DMA传送和CPU同时发挥最高的效率)