大家早上好,今天分享前先简单聊几句。笔者经历过很多面试,有华为,商汤,中颖电子,Micron,大疆等大厂,也有许多初创公司,现在仍然在某大厂一线做开发。同时也面试过很多人,不乏一些从nxp,st,华为等大厂离职的程序员,也做过行业协议评审,代表公司承办和参加过国际行业技术会议。经历过多个行业,做过多种上市产品,包括家用水处理设备,国内多家车厂的汽车数字钥匙,参与研发过多项国内top厂商的手机芯片开发。
不管是嵌入式技术的终端产品还是半导体产品开发,代码能力都很重要,即便现在AI满天飞,但真正深度的程序员,最多用AI做些辅助工作,核心工作还是要自己设计和实现的。就像Linus说的那样“Talk is cheap, show me your code”。当然并不是说其他能力不重要,只是说代码才是程序员的硬技能,阅读手册,理解产品,对标竞品,挖掘专利这些当然也很重要,只不过这是另一个层面的问题了。代码能力很大程度上决定着面试官对你的评价,属于行业准入的敲门砖,其他能力都可以在工作中查漏补缺,逐渐增强。
大厂的面试都有很多轮,国内某大厂(HW)的面试是先要做一套性格测评,这个结果如果不符合就没有后续了,可以提前从网上看看前辈们的意见攻略获取帮助。然后是线上做面试题,难度从简单到困难不等。最后一道题是困难等级的,印象中好像是2个小时3道题,至少要做出两道才行。面试必须全程开摄像头和录屏。再后面就是线上的两轮面试,其中第一轮是自我介绍和手撕代码,面试官会现场提出问题,要求在纸上面写出解答过程,不要求严丝合缝,但必须思路清晰,步骤准确,也可能会让review前一轮的线上试题。再然后是部门leader的面试,这个更多的是判断这个人的潜力,性格,稳定性等方面。
另一家某国际知名半导体企业(M)的面试也分成几轮,第一轮是电话技术面试,大约1小时,会问许多经验性的问题,看看项目实战能力和对研发过程中的问题的理解和解答能力。然后是现场面试,大约1小时,题量偏大,涉及到链表,队列,堆栈等操作,有单链,也有双链,还有些问题需要自己判断采用哪种结构,有些问题需要综合两种数据结构才能解决。总之大家,真正的能力需要时时积累的,如果侥幸进入了,也是要大量补课才能真正的扛起来自己的工作内容。
涉及的技术栈真的是五花八门,有C语言,数据结构,操作系统,至少是freeRTOS的一些原理和机制,GIT的具体使用场景和常用指令定义,gdb的使用方法,gcc的一些特征和代码优化,存储相关,FLASH与rom的特征和区别,OTA的设计,产品如何从软硬件两方面防止剽窃等等方面。
好了,下面开始今天的分享吧,内容都来自于以前的一些笔记,欢迎大家关注。
- 根据要求定义如下变量
/*
(1)一个整型数: int a。
(2)一个指向整型数的指针(一重指针): int *a。
(3)一个指向指针的的指针,它指向的指针是指向一个整型数的指针(二重指针): int **a。
(4)一个有10个整型数的数组 :int a[10]。
(5)一个有10个指针的数组,这10个指针是指向整型数的(指针数组): int *a[10]。
(6)一个指向有10个整型数数组的指针(数组指针):int (*a)[10]。
(7)一个指向函数的指针,该函数有一个整型参数并返回一个整型数(函数指针):int (*a)(int)。
(8)一个有10个指针的数组,这10个指针均指向函数,该函数有一个整型参数并返回一个整型数(函数
指针数组)
*/
int a; // An integer
int *a; // A pointer to an integer
int **a; // A pointer to a pointer to an integer
int a[10]; // an array of 10 integers
int *a[10]; // an array of 10 pointers to integers
int (*a)[10]; // A pointer to an array of 10 integers
int (*a)(int); // A pointer to a function that takes an integer as an
argument and returns an integer
int (*a[10])(int); // An array of ten pointers to functions that take an
integer argument and return an integer
- 完成代码
// 填写空白处的值,使其两次输出相同
void function (void)
{
int a[3][4][5];
int *p = a;
printf("%d, %d\n", p[5],p[21]);
printf("%d, %d\n", a[][][], a[][][]); // printf("%d, %d\n",a[0][1][0], a[1][0][1]);
return;
}
// 空白处插入代码,实现链表逆转
typedef struct linknode
{
int data;
struct linknode *next;
}node;
node *reverse(node *head) // 将一个链表逆置
{
node *p, *q, *r;
p = head;
q = p->next;
while(_____) // q != NULL
{
r= q->next;
______; // q->next = p;
p = q;
q = r;
}
______; // head->next = NULL;
head = p;
return head;
}
- 下面的声明都是什么意思?
const int a; // a是一个整型常量
int const a; // a是一个整型常量
const int *a; // a是一个指向整型常量的指针变量
int * const a; // a是一个指向整型变量的指针常量
int const * const a = &b; // a是一个指向整型常量的指针常量
char *strcpy(char *strDest, const char *strSrc); // 参数在函数内部不会被修改
const int strcmp(char *source, char *dest); // 函数的返回值不能被修改
- #与##的作用?
// #是把宏参数转化为字符串的运算符,##是把两个宏参数连接的运算符。例如:
#define STR(arg) #arg // 则宏STR(hello)展开时为”hello”
#define NAME(y) name_y // 则宏NAME(1)展开时仍为name_y
#define NAME(y) name_##y // 则宏NAME(1)展开为name_1
#define DECLARE(name, type) typename##_##type##_type // 则宏DECLARE(val, int)展开为int val_int_type
- Heap与Stack的差别?
//Heap是堆,空间可调整,手动分配和释放,可用于malloc分配内存空间
//Stack为栈,空间有限,编译器自动分配和释放, 例
int a = 0; //全局初始化区
char *p1; //全局未初始化区
void main(void)
{
int b; //栈
char s[] = "abc"; //栈
char *p2; //栈
char *p3 = "123456"; //123456\0在常量区,p3在栈上
static int c =0; //全局(静态)初始化区
p1 = (char *)malloc(10); //堆
p2 = (char *)malloc(20); //堆
}
6.请查看如下程序,在STM32上运行:
int a = 3;
int b[] = {3,4,5,6,7};
char*cstr = “my name is hypwr”;
int* ptr = (int*) cstr;
// 分别写出如下输出
printf(“%d %d”,sizeof(a),a); //
printf(“%d %d”,sizeof(b), b[3]); //
printf(“%d, %s”,sizeof(cstr),*cstr++); //
printf(“%d %d”,sizeof(ptr), *ptr); //
- 大小端原理,判定方法,转换方法例如:int a=0x12345678; //a首地址为0x200,大端存储格式如下:

// 小端:一个数据的低位字节数据存储在低地址 大端:一个数据的高位字节数据存储在低地址
/* 大小端各自的优点是什么?
(1)大端优点:符号位在低地址的第一个字节中,便于快速判数据的正负和大小。
(2)小端优点:CPU做数值运算的时候是依次从内存的低位到高位取数据进行运算,这样运行效率更高。
强制转换数据不需要调整字节内容,因为1、2、4字节数据的存储方式一样。*/
/* 如何判读一个系统的大小端存储模式 */
// 方法一:int *强制类型转换为char *,用“[]”解引用
void checkCpuMode(void)
{
int c = 0x12345678;
char *p = (char *)&c;
if(p[0] == 0x12)
printf("Big endian.\n");
else if(p[0] == 0x78)
printf("Little endian.\n");
else
printf("Uncertain.\n");
}
// 方法二:int *强制类型转换为char *,用“*”解引用
void checkCpuMode(void)
{
int c = 0x12345678;
char *p = (char *)&c;
if(*p == 0x12)
printf("Big endian.\n");
else if(*p == 0x78)
printf("Little endian.\n");
else
printf("Uncertain.\n");
}
// 方法三:包含short跟char的共用体
void checkCpuMode(void)
{
union Data
{
short a;
char b[sizeof(short)];
}data;
data.a = 0x1234;
if(data.b[0] == 0x12)
printf("Big endian.\n");
else if(data.b[0] == 0x34)
printf("Little endian.\n");
else
printf("uncertain.\n");
}
/* 大小端转化:对一个输入的整型数进行大小端存储模式转化
思路:大小端转化就是将一个整型数的低字节放到高字节,高字节放到低字节,跟前面的位翻转类似,只
不过这里的单位是字节,因此需要将位翻转中的&0x01改为&0xFF,<< bit改为size * 8,>>= 1改为
>> 8。
*/
int endian_convert(int input)
{
int result = 0;
int size = sizeof(input);
while(size--)
{
result |= ((input & 0xFF) << (size * 8));
input >>= 8;
}
return result;
}
更多精彩内容,敬请关注,笔者正在寻找和整理的笔记,期望尽快能发出整理的笔记合集,对大家能够有些帮助。敬请关注。
5338

被折叠的 条评论
为什么被折叠?



