C++面试突击(2)
1、volatile关键字作用?
分析:这个关键字主要用于告诉编译器:这个变量的值可能会被程序外的其他代码修改,不需要对这个变量值的访问进行优化,必须每次都是从这个参数的内存中直接读取或写入。因为优化过后这个变量的值就会存放在缓存区,相当于不变的值。
2、数组越界有什么危害?
分析:数组越界可能引发程序崩溃和安全漏洞。因为数组越界是值程序访问了不属于数组分配的内存区域,因为数组的内存区域是连续的,原定大小的内存区域存放数据,紧接着的内存是存放返回的地址,假如黑客在原定数据大小后输入他程序代码的地址,那程序就会跳转到黑客代码的执行地址,产生安全漏洞。所以编程的时候必须严格检查数组边界,使用安全函数。
3、栈泄露有什么危害?
分析:栈泄露与堆内存泄露不同,堆内存泄露是说分配的内存没有及时被free/delete回收,栈泄露更准确的说法是栈空间滥用或栈空间耗尽。主要原因是:深度递归、定义过大的局部变量。危害首先肯定还是会造成程序崩溃和安全漏洞,原因和第2个问题一样,还有一个危害是会损害其他数据,因为相邻的数据的内存可能会被这个溢出的栈给占用。
4、递归在单片机中使用会有什么问题?
分析:还是内存的问题,单片机的资源有限,递归过深的话首先造成的问题就是上面的第3个问题:栈溢出,也就是内存耗尽,从而引发程序崩溃。大部分单片机的RAM大小为几KB到几十KB,栈空间通常会被静态分配,然后每次调用就会消耗一次,递归调用n次,就消耗n×栈帧大小。所以可能出现的问题还是栈溢出、资源不足和性能下降。
5、任务间/进程间通信方式有哪些?这些优缺点是什么?适合什么场景?
分析:先说一下概念,任务间通信是涵盖进程通信、线程通信与协程通信的总称,进程间通信是一个子集,指相互隔离的进程如何进行通信。回到问题,任务间通信方式有管道通信、消息队列、共享内存、信号量、互斥锁等。下面举个例子来说明这些方式的优缺点。
任务间通信就像“人与人之间的交流”;
进程间通信就像“两个住在不同房子里的人进行交流”,这个就要通过特定的方式,比如打电话(类似消息队列),通过社区公告板(类似共享内存)、寄信(类似管道)来沟通。
线程间通信就像“住在同一个房子里的几个人进行交流”,他们可以随时面对面的说话(类似共享变量),但是要定下规则,谁先使用谁后使用,避免同时说话听不清(类似互斥锁同步)。
小结,可以分为三类:
一、基于共享的。
只要涉及到共享的,都需配合信号量和互斥锁机制,例如共享内存或共享变量,否则会出现数据不一致的情况,这种情况也叫数据竞争,这是共享内存的缺点,优点是访问速度快,传输数据量大。
二、基于消息传递的。
消息队列,优点是不需要同步,进程A把消息放进队列,进程B再从队列取出消息,这个放消息和取消息的过程不需要同时进行,这是一个优点,在嵌入式系统里经常用到。缺点是这个数据需要在用户态和内核态之间拷贝,对于超大消息来说效率会比较低。
管道,有匿名管道和命名管道,匿名管道是用于有亲缘关系的进程,如父子进程,是单向的;命名管道是可以用于无亲缘关系的进程间通信。所以管道的优点是实现简单,符合人们直观的“数据流”的概念,因为就像写完信去寄信一样。缺点就是这个是单向的,如果想实现双向通信,那就要我寄信给你,你也要寄信给我。
信号,是一种通知方式,只用来通知,不用于传输数据。适合用来处理一些异常、中断等。
三、基于同步的通信。
信号量,相当于一个计数器,用来控制多个任务对多个资源的访问。优点就是解决了同步的问题,缺点就是使用不当容易出现死锁,也就是两个任务互相等待对方。
互斥锁,也是和信号量类似的机制,一个二值信号量(0/1),确保一次只有一个任务访问某个共享资源。这两个的使用场景就是在需要保护共享资源的情况下使用,例如修改全局变量等。
套接字,通过网络协议进行通信,可以用于同一台机器上的进程间通信,叫本地套接字;也可以用于不同机器间的网络通信。优点是可以跨主机,缺点是开销大,因为要经过网络协议栈。适用于网络应用通信,例如Web服务器、游戏聊天软件等。
---------------------------------------------- END 欢迎批评指正! ----------------------------------------------