大家周一好,这篇文章转自我的朋友李纳克斯,在做工作的同事,去面试也能增长自己的技术面和技术深度。推荐给大家,希望对大家有所帮助。
某个下午,小鹏汽车的HR在招聘软件上撩我,于是我决定去聊聊看。
接触下来对他们的印象还不错,这家公司的面试风格非常的“美式”,二面三面的主考官都是美国人,有一个还是从苹果公司挖过来的,现在还在国外。面试出的题也很有意思,不考编程不问技术的,像三面就只考一道逻辑推理题,着实非常的有风格。
总体经历跟上次哔哩哔哩面试非常相似,四面以后的就不涉及技术了,不过前三次技术面试还是很有价值的,跟大家分享一下,希望能对大家有一些帮助。
面试岗位:小鹏汽车自动驾驶视觉方向C++岗
一面:纯技术
一面的面试官是个带广东口音的小哥,性格比较开朗有趣,我们俩相谈甚欢。
我们首先聊了聊普通消费者对于自动驾驶的认知,L1~L5这些等级区别。然后他抛出一个问题说,你认为“小鹏汽车过去一年内自动驾驶的死亡率为0”这句话能否让你认为小鹏的自动驾驶是安全的?
我说当然不能,对我而言除了死亡,受伤也是不可接受的,要体现绝对安全的话应该说事故率为0或者无任何人员受到伤害。
当然如果目前的技术还不能做到绝对安全这一点的话,我们在广告语上可以着重去体现自动驾驶在高速上或者路况良好的路段带给驾驶员的方便和帮助。
他对我的回答不置可否。
然后我们切入正题。
1-IIC协议和SPI协议的区别,如何选择用什么协议?
IIC协议只有CLK和DATA两根线,发送数据前需要先发送设备地址加读写操作选择,确定目标设备和数据传输方向。
SPI相对IIC协议有四根线,除CLK外还有片选信号和MOSI/MISO,并且是全双工模式,速率较高。
2-volatile关键字的作用,什么时候会用到?
volatile可以防止变量被编译器优化,每次读取变量时都直接从变量地址中读取数据。如果这个变量是多任务共享的,或者一些状态判断的寄存器的值需要用volatile修饰。
3-多态的实现原理
当类中声明虚函数时,类里会生成一个虚函数表Vtbl,表里存储了实际要执行的函数指针;类实例化的每个对象都会有一个指向虚函数表的虚表指针Vptr。
父类指针指向子类对象时,调用虚函数实际上调用的是子类对象的Vptr,指向子类的Vtbl,故而实现了多态。
4-多重继承时,多态如何实现?
多重继承时,对象的虚表指针用来指向自己所属类的虚表,虚表中的指针会指向其继承的最近的一个类的虚函数。
5-右值引用的作用
主要是移动语义,具体场景是移动构造、按值返回、对象存入容器可直接构造等。以及不太常用的完美转发的场景。
6-智能指针的作用
上次B站面试的时候提过,C++基础题了。用RAII的思想,将资源用对象的方式处理,在析构函数中释放资源。unique_ptr保证独占,没有拷贝构造函数,shared_ptr有引用计数,weak_ptr不参与引用计数,可以解决循环引用的问题。
7-如何不用中间变量,直接交换两个变量的值?
这个方法就多了,介绍一种异或的方法。
a = a^b;
b = a^b;
a = a^b;
除了对简历上我的项目经历过了一遍外,又对编译器开发和嵌入式开发做了一些细致提问,都在射程范围之内。
于是愉快的通过了一面。
二面:纯技术
二面的面试官是个美国人,说是刚从苹果跳槽到小鹏的,目前base在美国,所以我们面试还对了下时差,挑了上午11点面试。
1-什么时候用多态,什么时候用模板?
模板属于泛型编程,是在编译期实例化的,而多态是运行期确定的。在设计函数时,如果类型是同一层次的,并且类型不会影响函数内容,就用模板;反之如果类型有继承关系或类型会影响函数内容,那就用继承多态。
2-const比define应该尽量用哪个?
这个问题一出来我就笑了,前两天写《据说从未有人敢在简历上写精通C++》这篇文章的时候刚好把《Effective C++》这本书回顾了一下。于是我说这是《Effective C++》这本书的条款02所讲的内容。面试官也笑了说,是的我们都读过,那你把条款02讲讲吧。
我说条款02讲述的思想其实是“宁以编译器代替预处理器”。define是预处理器做的工作,只是单纯的字符替换;对于单纯变量来说,可用const代替,相比于define来说这样有类型检查,代码调试时也有这个变量;如果define定义了形似函数的函数的宏,则可改用inline内联。
3-移植linux系统时的步骤
这个看实际项目了,我拿我用cortex-A9芯片移植系统的步骤举例,先去官网下载uboot,kernel,去ubuntu官网下载最小系统制作fs。根据硬件部门给的原理图改设备树地址等等。
4-linux系统驱动分哪几种?网卡驱动属于哪一种?
字符设备驱动:led,key,显卡,串口等;
块设备驱动:U盘,SD卡,eMMC Flash等;
网络设备驱动,网卡驱动属于这类。
5-你做过哪些驱动的移植?他们之间有什么不同?
字符设备和块设备驱动居多,主要区别就是字符设备是以字符流形式访问的,块设备可以随机访问吧。
6-linux开发板从上电到启动系统的步骤?
这个流程也是面试的高频考点了,甚至可以单开一文详细讲讲工作这几年移植系统踩过的坑。面试的时候我大概是这么说的:
1.硬件同事一般会在板子上留个启动方式的切换,比如拨码开关或跳线帽,来决定是SD卡启动或Flash启动;
2.系统上电,执行第一阶段引导程序,IPL(Initial Program Loader)或者叫FSBL(First Stage Boot Loader),一般这部分程序是固化在芯片内部的BootROM里,寻找可以用来启动的设备。不过我之前用的一款xilinx的芯片也可以自己load这部分程序。
这段程序负责从第一步指定的设备中读取SPL(Secondary Program Loader)或者叫SSBL(Second Stage Boot Loader)到片内SRAM;
3.运行SPL,它完成CPU的初始化,DDR的初始化等,将真正的Uboot从存储设备搬到外部RAM中执行;
4.在Uboot中读取内核、根文件系统、设备树,加载到内存地址中;
5.将启动参数传递给内核,跳转到内核运行;
6.内核初始化,挂载根文件系统并启动。
7-在从SD卡往内存搬移系统时,谁初始化了内存?这个发生在什么阶段?
我理解里是SPL干了这件事。
8-一道编程题
至此聊天结束,开始动手了。面试官出了一道编程题,如下:
有n盏灯,编号为1~n。第1个人把所有灯打开,第2个人按下所有编号为2的倍数的开关(这些灯将被关掉),第3个人按下所有编号为3的倍数的开关(其中关掉的灯将被打开,开着的灯将被关闭),依此类推。一共有k个人,问最后有哪些灯开着?输入n和k,输出开着的灯的编号。k≤n≤1000。
我面试的时候是这么做的:
int func(int k,int n){if(k>n||n>1000){return -1; }std::vector<bool> leds;for(int i=0;i<n;i++){leds.push_back(false);}for(int j=1;j<=k;j++){for(int i=0;i<n;i++){if((i+1)%j==0){leds[i]=!leds[i]; }} }for(int i=0;i<n;i++){if(leds[i]){std::cout<<"num:"<<i+1<<std::endl;} }return 0;
}
要不要尝试来个别的解法?
9-一道逻辑题
三面:就一道题
三面就一道题,真的相当有风格。不问来历,不看出身,不考技术,不用编程,不听故事,就一道智力题。答对就过,答不上来就凉,很有意思。
三面之前我还想着都第三轮了,这个团队负责人应该不问技术细节了吧,应该会考察行业知识和个人素质了吧。我还去看了看小鹏去年的财报,了解了下从创业至今推出的产品线以及产品定位,目标用户,市场反馈,结果全没用上。
人家就问怎么把1到9这9个数填入九宫格......
小鹏汽车的团队负责人貌似国外的比较多?二面和三面的主考官都是说人在美国,刚下飞机,熟人太多,利益相关....面试到后期也是都喜欢考逻辑题。
这些看起来像是小学奥数题或者某些杂志广告页的逻辑推理题,蒙对个答案其实不难,但人家也不只是要个答案,能逻辑严谨的证明,找出所有的规律才算过关。打算面试小鹏汽车技术岗的朋友去之前最好多刷点类似的题。
祝大家都能找到理想(理想如果去不了,小鹏和蔚来也不错)的工作。
SHOW.TIME 点击关注.
微信公众号 | 李纳克斯Linux