嵌入式C语言面试经验总结

1 篇文章 0 订阅
1 篇文章 0 订阅
本文深入浅出地讲解了CPU、寄存器、缓存、内存的工作原理,以及栈、堆、静态存储区、常量区和代码区的内存分配。涉及变量理解、内存管理、操作系统概念、进程间通信、内存泄漏与溢出、数据结构与算法、编程内存操作和多线程同步等内容。
摘要由CSDN通过智能技术生成

对cpu、寄存器、缓存、内存的大概了解:

  1. 一般市场上的cpu和寄存器、缓存封装出售,cpu每次都要在寄存器存取,寄存器是个临时存取空间,寄存器去访问cpu,在寄存器和cpu之间有个缓存(cache),将常用的数据存到缓存上,缓存有三级缓存(1,2,3),价格和速度依次降低,寄存器要获取的变量能不能在缓存中获取到就涉及到命中率问题,如果获取不到,就直接从内存去拿;

  2. 栈区:存放函数的参数值、局部变量等,由编译器自动分配和释放,通常在函数执行完后就释放了,其操作方式类似于数据结构中的栈。栈内存分配运算内置于CPU的指令集,效率很高,但是分配的内存量有限,比如iOS中栈区的大小是2M。

  3. 堆区:就是通过new、malloc、realloc分配的内存块,编译器不会负责它们的释放工作,需要用程序区释放。分配方式类似于数据结构中的链表。在iOS开发中所说的“内存泄漏”说的就是堆区的内存。

  4. 静态区:全局变量和静态变量(在iOS中就是用static修饰的局部变量或者是全局全局变量)的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后,由系统释放。

  5. 常量区:常量存储在这里,不允许修改。

  6. 代码区:存放函数体的二进制代码。

类型说明符

  1. 类型说明符 void、char、short、int、long、signed、unsigned、float、double、struct、enum、union

  2. 存储类型 extern、static、register、auto、typedef、(变量有且只能有一个限定)

  3. 类型限制符 const(只读)、volatile

对变量的理解:

  1. extern:用在全局变量上表示该变量在其他文件中已经定义;用在函数上作用同全局变量;

  2. static:用在全局变量上,和非静态全局变量相比,限定了作用空间;用在局部变量上,把局部变量存到了静态存储区,延长了变量生存空间;用在函数上表示仅限当前文件使用

  3. register:将频繁使用的变量放到通用寄存器中,避免频繁访问内存,直接从寄存器中取值,提高cpu的工作效率;注:只能将局部变量或形式参数定义为寄存器变量,一般较短的变量类型适合定义为寄存器变量,如short、char等;

  4. auto:c语言变量缺省存储类型就是auto

  5. typedef:给变量或变量表达式换一个别名;

  6. const:只读变量;但是能通过指针去修改局部const变量,const变量是一个编译期间的常量;

  7. volatile:1)、易变性;所谓的易变性,在汇编层面反映出来,就是两条语句,下一条语句不会直接使用上一条语句对应的volatile变量的寄存器内容,而是重新从内存中读取。volatile的这个特性,相信也是大部分朋友所了解的特性;2)、“不可优化”特性。volatile告诉编译器,不要对我这个变量进行各种激进的优化,甚至将变量直接消除,保证程序员写在代码中的指令,一定会被执行;3)、C/C++ Volatile变量间的操作,是不会被编译器交换顺序的。(中断、多线程)

c程序的内存分配:

  1. 堆、栈、静态存储区、文件分配区(常量字符串)、程序分配区(二进制代码)

sizeof与strlen

  1. sizeof是关键字,对于数组来说就是申请的长度,对于指针来说就是4/8(看系统位数)

  2. strlen对于字符串来说,就是计算‘\0’之前的长度;

函数的参数传递:

  1. 值传递

  2. 引用传递

  3. 指针传递

  4. 数组地址传递

Const、指针、int/char等组合的意义:

  1. const int x :表示变量只读,不可更改

  2. const char * x/char const *x:声明该指针变量指向的是常量,即该指针变量的内容可以改变,但是该内容指向的内容不可改变;如:const char *x = “helloworld”;,可以直接更改x,如x = ”hi“就可以成功,但更改x[0] = ‘u’就会失败;

  3. char *const x:声明该指针变量为常变量,即指针变量里面的内容不可改变,但是该内容指向的内容可以改变; const char *x = “helloworld”;不可以直接更改x,如x = ”hi“会失败,但更改x[0] = ‘u’就会成功;

  4. const char *const x:声明该指针变量里面的内容不可改变,同时该内容指向的内容亦不可改变;

数组和指针:

  1. sizeof的用法

  2. 占用内存(连续\不确定)

物理地址和逻辑地址

  1. 物理地址:加载到内存地址寄存器的地址,内存单元的真正地址;

  2. 逻辑地址:CPU所生成的地址;

linux进程间通信

  1. 有几种方式: 管道(pipe),信号量,消息队列,信号,共享内存,套接字

多线程&&多进程,同步异步

脚本编写(shell)及基本知识

strcpy和memcpy区别

  1. strcpy只能复制字符串,memcpy能复制任何内容
  2. memcpy会指定复制长度

内存泄漏和内存溢出

  1. 内存泄露是指申请的内存没有释放,导致可用内存越来越少;

  2. 内存溢出指程序要用的内存大于可用的内存,如数组的使用,strcpy的使用

switch的变量允许哪些类型?不允许哪些类型?

  1. 整形、bool、字符、枚举;不允许字符串等非基本类型;

怎么防止头文件重复调用导致的编译问题;

  1. 在头文件中添加#ifndef 变量 / #pragma once

实时操作系统有哪些?怎么理解?路由器用的什么操作系统?

  1. FreeRTOS、Ucos

指针数组和数组指针,双重指针?

  1. 对指针数组来说,首先它是一个数组,数组的元素都是指针,也就是说该数组存储的是指针,数组占多少个字节由数组本身决定;而对数组指针来说,首先它是一个指针,它指向一个数组,也就是说它是指向数组的指针,在 32 位系统下永远占 4 字节,至于它指向的数组占多少字节,这个不能够确定,要看具体情况。

  2. 指针数组如 char *x[10],指向数组的指针,如char *x[10]={“hello”,“world”};,x[0]=“hello”,x[1]=“world”

  3. 数组指针如 char (*x)[10],表示指针x指向char [10]数组,为匿名数组

  4. 双重指针如 char **x

内存相关问题?

结构体自增的含义,双重指针自增?

  1. 自增从右向左进行;

寄存器怎么用,怎么操作?

保存一些经常调用的数据,不再访问内存;

内核和驱动开发的理解?

路由器的进程怎么切换,怎么沟通?

arm问题和理解

怎么获取全局变量和局部变量的地址?(gdb)

  1. backtrace bt

进程中的同步,异步怎么用?

  1. 同步一般通过同步锁实现;

  2. 同步锁和自旋锁区别:一种是没有获取到锁的线程就一直循环等待判断该资源是否已经释放锁,这种锁叫做自旋锁,它不用将线程阻塞起来(NON-BLOCKING);还有一种处理方式就是把自己阻塞起来,等待重新调度请求,这种叫做互斥锁

进程和线程的关系和区别?

  1. 进程:进程是能在系统中独立运行并作为资源分配的基本单位,是CPU分配资源的最小单位,它包括独立的地址空间,资源以及一至多个线程。

  2. 线程:线程是进程中的一个实体,是CPU调度的最小单位。

树的遍历(递归&&非递归)

如利用中序遍历,左子树-根节点-右子树,根据堆栈的push和pop进行进栈和出栈的操作;

链表的排序(若结构体的数据类型不确定void *怎么办) && 链表反转

  1. 链表的排序

  2. 链表的反转:第一种方法是递归操作;第二种方法是迭代操作,即1->2->3,反转方向;

编译过程:预处理、编译、汇编、链接

宏定义有两个#的作用

  1. ##用来连接两个字符串

  2. 一个#:将后接项转成字符串

进程调度的几种方式:

  1. 先来先服务FCFS、时间片轮转、短作业优先 调度算法

tcp/ip各层的作用:

  1. 链路层:用来处理连接网络的硬件部分。包括控制操作系统,硬件的设备驱动,NIC(网络适配器,即网卡),以及光钎等物理可见部分(还包括连接器等一切传输媒介)。硬件上的范畴均在链路层的作用范围之内。

  2. 网络层:网络层来处理在网络上流动的数据包。数据包是网络传输的最小数据单位。规定了通过怎样的路径(所谓的传输路线)到达对方计算机,并把数据包传送给对方。与对方计算机之间通过多台计算机或者网络设备进行传输时,网络层所起的作用就是在众多的选项内选择一条传输路线。

  3. 传输层:传输层对上层应用层,提供处于网络连接中的两台计算机之间的数据传输。

  4. 应用层:应用层决定了向用户提供服务时通信的活动.

udp传输数据过程和关键字

  1. 创建客户端socket开始进行通讯。
  2. 这时服务端应该先启动,并在知道服务端的ip以及端口号的时候才能进行通讯。
  3. 本地不需要绑定ip以及端口号,在用此套接字对象发送消息的时候会自动分配活动端口(1024-65535)
    每次重启程序可能每次都不一样。
  4. 然后对将要发送的信息进行编码处理,然后将编码后的字节码发送到指定服务端ip以及端口。
  5. 这里还可以进行消息的接收,在这里接收消息首先得要发送数据到指定的服务端,告诉服务端客户端的ip以及所使用的端口是什么。
  6. 如果先进行消息阻塞是收不到消息的,这里客户端不需要绑定端口可以理解成在客户端把数据发送到服务端以后系统在后台默默地
    把客户端ip以及端口和客户端绑定了起来。这样服务端发送的消息就能被客户端所接收。
  7. 接受到消息同样要进行解码,解码形式与服务端发送过来数据的编码格式相对应,把字节码转换成能看懂的数据进行打印。
  8. 最后进行客户端udp套接字关闭。
  9. 关键字:目的ip,源ip,目标端口,源端口等;

回调函数

  1. 字面上的理解,回调函数就是一个参数,将这个函数作为参数传到另一个函数里面,当那个函数执行完之后,再执行传进去的这个函数。这个过程就叫做回调。

读写文件:

File *fp;
fp = fopen(file,“r”)!=NULLwhile(!feof(fp))
{
     if(fgets(str,128,fp)!=NULL)
      printf("%s",str);
}
fclose(fp);

各种排序:

原子操作

  1. 所谓原子操作就是指不会被线程调度机制打断的操作;这种操作一旦开始,就会执行到结束;

volatile的理解

  1. volatile的作用是告知编译器,它修饰的变量随时都可

  2. 作用:在进行编译时不优化,在执行的时候不缓存, 每次都需要从内存中读出(保证内存的可见性)

  3. 场景:多用于多线程或多CPU编程能被改变,因此,编译后的程序每次在使用该变量的值时,都会从变量的地址中读取数据,而不是从寄存器中获取;

锁、同步异步的理解

一个进程结束后怎么调用另一个进程(同步的实现)

  1. 事件;用来通知线程有一些事件已发生,从而启动后继任务的开始。

  2. 进程同步:临界区、互斥量、事件、信号量

消息队列

进程通信的一种方式,进程间通信包括几种方式:pipe,信号量,消息队列,信号,共享内存,套接字;

segment fault

  1. 長話短說, 就是軟件訪問了不該訪問的memory, 而硬件具有內存保護功能. 具體的說, 就是當内存管理单元檢測到非法內存被訪問了, 那麼它就讓CPU產生一個exception.

  2. 进程调度的流程 先来先服务,时间片轮转调度,短作业优先;

空指针(NULL)、void *

  1. 在C语言中,如果一个指针不指向任何数据,我们就称之为空指针,用NULL表示;void 指针与空指针 NULL 不同:NULL 说明指针不指向任何数据,是“空的”;而 void 指针实实在在地指向一块内存,只是不知道这块内存中是什么类型的数据。

static变量存在头文件中

  1. 不同文件调用的static变量不是同一个变量,地址都不同;若要实现头文件的全局变量,用extern变量;

写一遍多进程、多线程,配合互斥锁

  1. 互斥锁:pthread_mutex_t变量,用pthread_mutex_init(地址,null)初始化,用pthread_mutex_lock(地址)和pthread_mutex_unlock(地址)获得锁和释放锁;

  2. 多线程:pthread_t 变量; ret = pthread_create(&变量,NULL,函数名,NULL); pthread_join(变量名);

系统调用过程

wifi的具体工作原理?

  1. 连接过程
  2. 连接过程中的四次握手
  3. wpa2\wpa3的区别
  4. 加密方式的区别, tkip/aes, ccmp等
  5. Wi-Fi认证过程
  6. Mpdu、Msdu

voip的基本用法

帧聚合

  1. 在信道的竞争中所产生的冲突,以及为解决冲突而引入的退避机制都大大降低了系统的吞吐量。802.11n为了解决MAC层的这两个问题,采用了帧聚合(Frame Aggregation)技术和Block Acknowledgement机制。

  2. A-MSDU技术是指把多个MSDU通过一定的方式聚合成一个较大的载荷。这里的MSDU可以认为是Ethernet报文;

  3. 与A-MSDU不同的是,A-MPDU聚合的是经过802.11报文封装后的MPDU,这里的MPDU是指经过802.11封装过的数据帧。

  4. A-MPDU需要结合Block Acknowledgement技术,802.11发送设备通过连续发送若干个MPDU(个数要少于BA的buffer size),

  5. 802.11接收设备只需回复一个Block ACK,从而减少信道竞争所消耗的时间, 提高了系统吞吐量.

dcf(基于csma/ca机制,分布式协调功能):

  1. csma/ca指载波侦听多路访问/碰撞避免;(两个client竞争向ap发送数据的过程)

  2. DIFS:分布式帧间间隔; SIFS:slow帧间间隔;竞争窗口;slot time:空闲时间;

  3. Backoff:随机回退过程是指每一个节点在竞争信道时,所经历的随机退避过程;

  4. 过程:两个client分别有数据要发送,首先经过difs时间,然后到backoff的过程,选择指定的竞争窗口数字,然后根据slot time递减,若随即递减数字为0,就开始发送数据,发送完数据后,ap会进行crc检验,若没问题,ap就会在sifs时间后反馈ack帧,一次传输过程就结束了;若没有收到反馈,则会进入EIFS时间,过一段时间再进行传输;

active scan和passive scan

  1. passive scan:通过监听每个信道上,AP 定时发出的 beacon 帧,从而扫描到 AP 的详细信息;

  2. active scan:在每个信道发送 probe request 帧来发送请求发现 AP, 如果 AP 同意其发现自己,发送 probe respond 帧来回复;

lan,wlan,wan

  1. lan指局域网络, wlan指无线局域网, wan指广域网,连接外网;

路由转发原理

路由器的架构

clan

指针和引用的区别

  1. 引用是别名,指针是地址;指针在运行时可以改变所指向的值,而引用一旦与某个对象绑定后就不再改变;程序为指针变量分配区域,而不为引用分配内存区域;程序在编译时分别将指针和引用添加到符号表上,符号表上记录的是变量名及变量所对应地址;从理论上来说,对于指针没有级数限制,但是引用只有一级;两者的效率是一致的,因为在底层中,指针和引用的参数都指向同一个地址;

C语言基础

  1. 栈的大小,堆的大小,malloc可申请的最大内存,受到什么限制?
    (1). 栈的大小:
    —Linux中测试不到2MB,理论值默认为8MB,ulimit -a/ulimit -s 可查;
    (2). 堆的大小不是个定值,malloc申请的最大内存,影响因素: malloc函数的实现方式、操作系统、硬件、当前内存的使用状况;
  2. 函数调用过程,参数怎么压栈?
    每次函数调用过程中,都会有一个自己的栈帧,维护相关信息;首先栈底指针入栈,然后函数参数(<=4)时,函数参数逆序依次入栈(通过寄存器r0,r1,r2,r3)保存,运算后将入栈,将结果入栈,将结果存入r0寄存器,调用函数帧栈的sp指向栈底fp,释放被调用栈空间,fp出栈。(被调函数栈帧中的fp是调用函数的sp)
  3. struct结构体,怎么根据成员地址获取struct变量的地址?是否有相关的API可用?
    如果结构体里成员变量比较复杂,那么手动计算成员地址和结构体地址的联系的方式有点慢,kernel有一个宏如下:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
  1. 上面这个宏的意思是假如结构体存放在地址为0处,结构体地址为A,也为0,成员MEMBER地址为B,那么成员的偏移为B,结构体即得到成员的偏移量。那么用(char *)&member-(char *)偏移量即可算得结构体的地址。
  2. C程序的内存分布情况?Stack的增长方向?Heap的增长方向?
    在这里插入图片描述

Linux系统基础

  1. Linux系统调用的方式?
    —软中断、syscall(不太理解…)
    —常用的系统调用:fork、exit、open、close
  2. ioctl是什么?
    —向驱动层发送或者接收指令
  3. 描述进程的数据结构?
    —Linux内核中使用 task_struct 结构来表示一个进程,这个结构体保存了进程的所有信息;
  4. 进程同步的方式?
    —信号量(semget、semctl、semop),
    —文件锁flock(),LOCK_SH 建立共享锁定,LOCK_EX建立互斥锁定, LOCK_UN解除文件锁定,LOCK_NB不阻塞申请锁;
  5. 线程同步的方式?
    —互斥锁(pthread_mutex_t )
    —信号量
    —读写锁:加写锁后,再加锁会阻塞;加读锁后,可以再加读锁,加写锁会阻塞;
  6. 有没有用过管道?进程间通信的方式?
    管道:管道通过内核缓冲区实现数据传输,有pipe和fifo两种管道,pipe是无名管道,半双工,只能在有亲缘关系进程间通信,通过pipe()系统调用创建和打开;fifo是命名管道,命名管道的名字对应于一个磁盘索引节点,半双工,通过mkfifo()/mknode()创建,不局限于有血缘关系的进程;
    进程间通信:socket、信号、信号量、消息队列、无名管道pipe、命名管道fifo、共享内存(shmget创建共享内存、shmat关联共享内存、shmdt去关联、shmctl销毁共享内存)
  7. 多路复用用过吗?
    select(一般最大连接数1024)、poll(链表存储文件描述符,最大连接数没限制,但需要遍历可用的描述符)、epoll(高并发使用)
  8. gdb怎么查看一个变量?调试方法?
    调试代码时,gdb调试,file 程序名;r运行程序;b设置断点,如b 8,b main;c顺序执行,直到遇到断点;p 变量名可查看变量值,但要在变量的下一行才可以查看;s顺序执行每条语句,遇到函数调用不进去;n与s类似,但遇到函数调用会执行;i可查看相关的信息, c表示继续运行程序
  9. shell怎么实现并发
    执行的语句加上&,后台执行,如下:
#!/bin/sh
for i in {0..9};
do
{
	echo "helloworld"
	sleep 1
}&
done

计算机网络

  1. 如果http发送的包比较大,怎么传输?MSS的大小由谁决定?分片和分包的区别?
    —IP分片是网络上传输IP报文的一种技术手段。IP协议在传输数据包时,将数据报文分为若干分片进行传输,并在目标系统中进行重组。这一过程称为分片。每一种物理网络都会规定链路层数据帧的最大长度,称为链路层MTU(Maximum Transmission Unit).IP协议在传输数据包时,若IP数据报加上数据帧头部后长度大于MTU,则将数据报文分为若干分片进行传输,并在目标系统中进行重组。
    —MSS(Maxmum Sigmentation Size)就是TCP数据包每次能够传输的最大数据分段。为了达到最佳的传输效能TCP协议在建立连接的时候通常要协商双方的MSS值,这个值TCP协议在实现的时候往往用MTU值代替(需要减去IP数据包包头的大小20字节和TCP数据段的包头20字节)所以往往MSS为1460。通讯双方会根据双方提供的MSS值的最小值确定为这次连接的最大MSS值。
  2. 数据包从client往server传输,server未成功接收数据,怎么分析问题?
    首先通过抓包查看tcp链接是否正常,然后查看端口是否被占用,然后查看iptables表是否会阻塞传输;
  3. iptables的用法?
    基于netfilter框架,有raw、mangle、nat、filte(默认表)四张表,有五条规则:PREROUTING、INPUT、FORWARD、OUTPUT、POSTROUTING,常用的控制类型有ACCEPT,DROP, REJECT,常用的指令如下:iptables -A(链尾添加),-I(链头添加),-D(删除), -nvL(查看链表),-F 清空链表, -t (指令表,默认为filter表),-s(源地址), --sport(源端口),-p(指定协议),-d(目的地址),–dport(目的端口), -i(包流入的网卡), -o(包流出的网卡).
    在这里插入图片描述
    在这里插入图片描述
  4. 有几种nat?
    SNAT(源地址)和DNAT(目的地址)
    snat:局域网访问互联网,dnat:当内部需要提供对外服务时
  5. 策略路由、静态路由如果配置?
    静态适用于目标地址确定,策略路由适用于区分端口访问的场景;(没太理解…)
  6. 说说NFS?
  7. 三次握手的理解?两次握手可以吗?除了保证收发能力,还有其他因素吗?
    —如客户端发出连接请求,但因连接请求报文丢失而未收到确认,于是客户端再重传一次连接请求。后来收到了确认,建立了连接。数据传输完毕后,就释放了连接,客户端共发出了两个连接请求报文段,其中第一个丢失,第二个到达了服务端,但是第一个丢失的报文段只是在某些网络结点长时间滞留了,延误到连接释放以后的某个时间才到达服务端,此时服务端误认为客户端又发出一次新的连接请求,于是就向客户端发出确认报文段,同意建立连接,不采用三次握手,只要服务端发出确认,就建立新的连接了,此时客户端忽略服务端发来的确认,也不发送数据,则服务端一致等待客户端发送数据,浪费资源
    —SYN攻击:当用户一直恶意请求与server的链接,如果是两次握手,一直发SYN包,server这边不要维持链接,浪费资源.
  8. 查看端口的方式?
    netstat命令
  9. 学习新技术的方法?
    (1). 基本技术,比如程序的语法等
    (2). 利用新技术完成小的项目
    (3). 归纳总结学习过程中遇到的坑和重点

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值