相遇皆是缘分

C&数据结构

关键字volatile有什么含意? 并给出三个不同的例子。

1
2
3
4
5
6
7
【参考答案】一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子:

1). 并行设备的硬件寄存器(如:状态寄存器)

2). 一个中断服务子程序中会访问到的非自动变量

3). 多线程应用中被几个任务共享的变量

关键字volatile有什么含意?

1
【标准答案】提示编译器对象的值可能在编译器未监测到的情况下改变。

头文件中的 ifndef/define/endif 干什么用?

1
【标准答案】防止该头文件被重复引用。

#include <filename.h> 和 #include “filename.h” 有什么区别?

1
2
3
【标准答案】
对于#include <filename.h> ,编译器从标准库路径开始搜索 filename.h ;
对于#include “filename.h” ,编译器从用户的工作路径开始搜索 filename.h 。

const 有什么用途?(请至少说明两种)

1
2
3
(1)可以定义 const 常量
(2)const 可以修饰函数的参数、返回值,甚至函数的定义体。被 const 修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。
const意味着"只读"

static

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
static有什么用途?(请至少说明两种)
【标准答案】
限制变量的作用域(static全局变量);
设置变量的存储域(static局部变量)。

static的作用
1.在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。
2.在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。
3.在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用。

A.c 和B.c两个c文件中使用了两个相同名字的static变量,编译的时候会不会有问题?这两个static变量会保存到哪里(栈还是堆或者其他的)?
【标准答案】
static的全局变量,表明这个变量仅在本模块中有意义,不会影响其他模块。
他们都放在静态数据区,但是编译器对他们的命名是不同的。
如果要使变量在其他模块也有意义的话,需要使用extern关键字。

static全局变量与普通的全局变量有什么区别?
【标准答案】 static全局变量只初使化一次,防止在其他文件单元中被引用;

static局部变量和普通局部变量有什么区别
【标准答案】static局部变量只被初始化一次,下一次依据上一次结果值;

static函数与普通函数有什么区别?
【标准答案】static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝

堆栈

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
队列和栈有什么区别?
【标准答案】队列先进先出,栈后进先出。

Heap(堆)与stack(栈)的差别。
【标准答案】Heap是堆,stack是栈。
stack(栈)的空间由操作系统自动分配/释放,Heap(堆)上的空间手动分配/释放。
stack(栈)是连续的地址空间,Heap(堆)不是连续的地址空间,很容易产生内存碎片,浪费内存。
stack(栈)由系统分配,分配速度较快,Heap(堆)一般较慢
stack(栈)是从高地址像低地址分配的,分配空间较小,Heap(堆)是低由地址向高地分配的,空间较大

程序的局部变量存在于栈(stack)中,全局变量存在于静态数据区 中,动态申请数据存在于 堆( heap)中。

用两个栈实现一个队列的功能?要求给出算法和思路!
【参考答案】设2个栈为A,B, 一开始均为空. 入队:
将新元素push入栈A; 出队:
(1) 判断栈B是否为空;
(2) 如果不为空,则将栈A中所有元素依次pop出并push到栈B;
(3) 将栈B的栈顶元素pop出;

写一个“标准”宏,这个宏输入两个参数并返回较小的一个。

1
2
3
4
【标准答案】#define Min(X, Y) ((X)>(Y)?(Y):(X))//结尾没有;
1.标识#define在宏中应用的基本知识。这是很重要的。因为在 嵌入(inline)操作符 变为标准C的一部分之前,宏是方便产生嵌入代码的唯一方法,对于嵌入式系统来说,为了能达到要求的性能,嵌入代码经常是必须的方法。
2.三重条件操作符的知识。这个操作符存在C语言中的原因是它使得编译器能产生比if-then-else更优化的代码,了解这个用法是很重要的。
3.懂得在宏中小心地把参数用括号括起来

用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题)

1
2
3
4
5
【参考答案】#define SECONDS_PER_YEAR (60 * 60* 24 * 365)UL
1.#define 语法的基本知识(例如:不能以分号结束,括号的使用,等等)
2.懂得预处理器将为你计算常数表达式的值,因此,直接写出你是如何计算一年中有多少秒而不是计算出实际的值,是更清晰而没有代价的。
3.意识到这个表达式将使一个16位机的整型数溢出-因此要用到长整型符号L,告诉编译器这个常数是的长整型数。
4.如果你在你的表达式中用到UL(表示无符号长整型),那么你有了一个好的起点。记住,第一印象很重要。

已知一个数组table,用一个宏定义,求出数据的元素个数。

1
【标准答案】#define NTBL(table) (sizeof(table)/sizeof(table[0]))

在 C++ 程序中调用被 C 编译器编译后的函数, 为什么要加 extern “C”?

1
2
3
【标准答案】
C++语言支持函数重载,C 语言不支持函数重载。
函数被 C++编译后在库中的名字与 C 语言的不同。假设某个函数的原型为: void foo(int x, int y); 该函数被 C 编译器编译后在库中的名字为_foo,而C++编译器则会产生像_foo_int_int 之类的名字。 C++ 提供了 C 连接交换指定符号 extern“C”来解决名字匹配问题。

代码分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// 1. 请写出下列代码的输出内容#include <stdio.h>
int main()
{
int a,b,c,d; a=10;
b=a++; c=++a; d=10*a++;
printf("b,c,d:%d,%d,%d",b,c,d);
return 0;
}
【标准答案】1012120

unsigned char *p1; unsigned long *p2;
p1=(unsigned char *)0x801000; p2=(unsigned long *)0x810000;
// 2. 请问p1+5= ; p2+5= ;
【标准答案】0x8010050x810020

void main()
{
int a[5]={1,2,3,4,5};
int *ptr=(int *)(&a+1);
printf(“%d,%d”,*(a+1),*(ptr-1));
}
// 3. 请问输出:
【标准答案】2,5

// 4. 以下是求一个数的平方的程序,请找出错误: #define SQUARE(a)((a)*(a))
int a=5; int b;
b=SQUARE(a++);
【标准答案】宏在预编译时会以替换的形式展开,仅仅会替换。涉及到宏的地方,不要用++ --,标准中对此没有规定,因此最终结果将会依赖于不同的编译器。执行程序的答案可能是25、也有可能是36

#define Max_CB 500
void LmiQueryCSmd(Struct MSgCB * pmsg)
{
unsigned char ucCmdNum;
......
for(ucCmdNum=0;ucCmdNum<Max_CB;ucCmdN um++)
{
......;
}
}

// 5. 这段代码执行有什么问题?
【标准答案】死循环
unsigned char //无符号字符型 表示范围0~255 char //有符号字符型 表示范围-128~127

int modifyvalue()
{
return(x+=10);
}
int changevalue(int x)
{
return(x+=1);
}
void main()
{
int x=10; x++;
changevalue(x); x++;
modifyvalue();
printf("First output:%dn",x); x++;
changevalue(x); printf("Second output:%dn",x); modifyvalue();
printf("Third output:%dn",x);
}

// 6. 输出?
【 标准答案】121313

// 7. 请写出下列代码的输出内容
#include<stdio.h> main()
{
int a,b,c,d; a=10;
b=a++; c=++a; d=10*a++;
printf("b,c,d:%d,%d,%d",b,c,d);
return 0;
}
【标准答案】1012120

// 8. 下面的代码输出是什么,为什么?
void foo(void)
{
unsigned int a = 6; int b = -20;
(a+b > 6)? puts("> 6") : puts("<= 6");
}
【参考答案】这个问题测试你是否懂得C语言中的整数自动转换原则,
我发现有些开发者懂得极少这些东西。不管如何,这无符号整型问题的答案是输出是“>6”。原因是当表达式中存在有符号类型和无符号类型时所有的数都自动转换为无符号类型。因此-20变成了一个非常大的正整数,所以该表达式计算出的结果大于6。这一点对于应当频繁用到无符号数据类型的嵌入式系统来说是丰常重要的。如果你答错了这个问题,你也就到了得不到这份工作的边缘。

// 9. 一语句实现x是否为2的若干次幂的判断。
void main()
{
int a; scanf(“%d”,&a);
printf(“%c”,(a)&(a-1)?’n’:’y’); // 若是打印y,否则n
}

// 10. 中断是嵌入式系统中重要的组成部分,这导致了很多编译开发商提供一种扩展—让标准C支持中断。具代表事实是,产生了一个新的关键字interrupt。下面的代码就使用了 interrupt关键字去定义了一个中断服务子程序(ISR),请评论一下这段代码的。
interrupt double compute_area (double radius)
{
double area = PI * radius * radius; printf(" Area = %f", area);
return area;
}
【参考答案】这个函数有太多的错误了,以至让人不知从何说起了:
1). ISR 不能返回一个值。如果你不懂这个,那么你不会被雇用的。
2). ISR 不能传递参数。如果你没有看到这一点,你被雇用的机会等同第一项。
3). 在许多的处理器/编译器中,浮点一般都是不可重入的。有些处理器/编译器需要让额处的寄存器入栈,有些处理器/编译器就是不允许在ISR中做浮点运算。此外,ISR应该是短而有效率的,在ISR中做浮点运算是不明智的。
4). 与第三点一脉相承,printf()经常有重入和性能上的问题。如果你丢掉
了第三和第四点,我不会太为难你的。不用说,如果你能得到后两点,那么你的被雇用前景越来越光明了

//11、请填写 bool , float, 指针变量 与“零值”比较的 if语句。
提示:这里“零值”可以是 0, 0.0 , FALSE 或者“空指针”。例如 int 变量 n 与“零值”比较的 if 语句为: if ( n == 0 ) if ( n != 0 ) 以此类推。
1) 请写出 bool flag 与“零值”比较的 if 语句:
【标准答案】if ( flag ) if ( !flag )
如下写法不得分
if(flag == TRUE) || if(flag == 1) || if(flag == FLASE) || if(flag == 0)

2)请写出 float x 与“零值”比较的 if 语句:
【标准答案】 const float EPSINON = 0.00001; if ((x >= - EPSINON) && (x <= EPSINON)
不可将浮点变量用“==”或“!=”与数字比较,应该设法转化成“>=”或“<=”此类形式。
如下写法不得分
if( x == 0.0) || if(x != 0.0)

3) 请写出 char *p 与“零值”比较的 if 语句
【标准答案】 if (p == NULL) if (p != NULL)
如下写法不得分
if(p == 0) || if(p)

//12以下为 Linux下的 32 位 C程序,请计算 sizeof 的值。
char str[] = “Hello” ; char *p = str ; int n = 10;
请计算
1sizeof (str ) =
2sizeof ( p ) =
3sizeof ( n ) =

【标准答案】(16、(24、(34

4void Func ( char str[100]){}
请计算 sizeof( str ) =
【标准答案】(44

5void *p = malloc( 100 );
请计算sizeof ( p ) =
【标准答案】(54

代码有什么问题?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
//1.
int main()
{
char a;
char *str=&a;
strcpy(str,"hello");
printf(str);
return 0;
}

【标准答案】没有为str分配内存空间,将会发生异常问题出在将一个字符串复制进一个字符变量指针所指地址。虽然可以正确输出结果,但因为越界进行内在读写而导致程序崩溃。

//2.
char* s="AAA";
printf("%s",s);
s[0]='B';
printf("%s",s);

【标准答案】“AAA” 是字符串常量。s是指针,指向这个字符串常量,所以声明s的时候就有问题。
cosnt char* s=“AAA”;
然后又因为是常量,所以对是s[0]的赋值操作是不合法的。


//3.
void getmemory(char *p)
{
p=(char *) malloc(100); strcpy(p,“hello world”);
}
int main( )
{
char *str=NULL; getmemory(str); printf(“%s/n”,str); free(str);
return 0;
}

【标准答案】: 程序崩溃,getmemory中的malloc 不能返回动态内存, free()对str操作很危险。

//4.
void main()
{
char aa[10];
printf(“%d”,strlen(aa));
}

【标准答案】sizeof()和初不初始化,没有关系,strlen()和初始化有关,打印结果值未知。

//5. 简述两个for循环的优缺点
for(i=0;i<N;i++)
{
if(codition)
DoSomething();
else
DoSomething();
}
优点:程序简洁
缺点:多执行了N-1次逻辑判断,并且打断了循环“流水线”作业,使得编译器不能对循环优化处理,降低了效率
------------------------------
if(codition)
{
for(i=0;i<N;i++)
DoSomething();
}
else
{
for(i=0;i<N;i++)
DoSomething();
}
优点:循环的效率高
缺点:程序不简洁

//6.问函数既然不会被其它函数调用,为什么要返回1?
int main()
{
int x=3;
printf("%d",x);
return 1;
}

【标准答案】mian中,c标准认为0表示成功,非0表示错误。具体的值是某中具体出错信息。

//7. 问sizeof(A) = ?
struct A
{
char t:4;
char k:4;
unsigned short i:8;
unsigned long m;
};

【标准答案】8

// 8.求sizeof(name1)?
struct name1{
char str;
short x; int num;
};

【标准答案】8

// 9.求sizeof(name2)?
struct name2{
char str;
int num;
short x;
};

【标准答案】12

//10 程序哪里有错误
wap( int* p1,int* p2 )
{
int *p;
*p = *p1;
*p1 = *p2;
*p2 = *p;
}
【标准答案】p为野指针

//11.ptr的结果是否相同?其中ptr为同一个指针。
(void *)ptr 和 (*(void**))
【标准答案】(void *)ptr 和 (*(void**))ptr值是相同的

/* 12.要对绝对地址0x100000赋值,我们可以用(unsigned int*)0x100000 = 1234;
那么要是想让程序跳转到绝对地址是0x100000去执行,应该怎么做? */

【标准答案】*((void (*)( ))0x100000 ) ( );
首先要将0x100000强制转换成函数指针,即: (void (*)())0x100000
然后再调用它:
*((void (*)())0x100000)();


/* 13. 嵌入式系统经常具有要求程序员去访问某特定的内存位置的特点。
在某工程中,要求设置一绝对地址为0x67a9的整型变量的值为0xaa66。
编译器是一个纯粹的ANSI编译器。写代码去完成这一任务。 */
【参考答案】这一问题测试你是否知道为了访问一绝对地址把一个整型数强制转换(typecast)为一指针是合法的。这一问题的实现方式随着个人风格不同而不同
。典型的类似代码如下:
int *ptr;
ptr = (int *)0x67a9;
*ptr = 0xaa55;

数组和链表的区别

1
2
数组:数据顺序存储,固定大小;
链表:数据可以随机存储,大小可动态改变

int (*s[10])(int) 表示的是什么啊

1
【标准答案】int (*s[10])(int) 函数指针数组,每个指针指向一个int func(int param)的函数。

堆栈溢出一般是由什么原因导致的?

1
【标准答案】没有回收垃圾资源。

数据声明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//1.一个整型数
int a;

//2.一个指向整型数的指针
int *a;

//3.一个指向指针的的指针,它指向的指针是指向一个整型数
int **a

//4.一个有10个整型数的数组
int a[10];

//5.一个有10个指针的数组,该指针是指向一个整型数的
int *a[10]

//6.一个指向有10个整型数数组的指针
int (*a)[10];

//7.一个指向函数的指针,该函数有一个整型参数并返回一个整型数
int (*a)(int);

//8.一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数
int (*a[10])(int);

//9.一个整型数
int a;

//10.一个整型数
int a;

//11.一个整型数
int a;

//12.一个整型数
int a;

请问进程和线程有什么区别?

1
2
我理解的进程它其实就是一个APP吧
就比如说我们在电脑上打开任务管理器,然后它里面就会有很多的一个进程列表,比如说一个QQ它就是一个进程比如说一个英雄联盟他就是一个进程,进程他是我们操作系统资源分配的一个基本单位,在一个进程里可以拥有一个或者多个线程,当一个进程里面只有一个线程,我就理解为他们没什么区别,如果一个进程里面有多个线程就不一样了,多个线程它其实是共享进程的一个资源的,然后这就导致了在同一个进程里面某一个线程挂了就有可能会导致其他的线程也会出问题,但是每一个进程之间是相互独立的 线程是CPU调度的一个基本单位

什么是空指针

1
也就是说,空指针不会指向任何地方,它不是任何对象或函数的地址。简单点说,一个指针不指向任何数据,我们就称之为空指针,用NULL表示。

什么是野指针

1
野指针是指向一个不可知地址的指针

多态的定义

1
同字面意思意为多种形态,本质就是不同对象完成同一行为产生的不同结果

链表和数组的区别

1
数组是顺序存储结构,链表是链式存储结构。

重载重写的区别

1
2
3
4
5
6
定义不同---重载是定义相同的方法名,参数不同;重写是子类重写父类的方法
范围不同---重载是在一个类中,重写是子类与父类之间的
多态不同---重载是编译时的多态性,重写是运行时的多态性
返回不同---重载对返回类型没有要求,而重写要求返回类型,有兼容的返回类型
参数不同---重载的参数个数、参数类型、参数顺序可以不同,而重写父子方法参数必须相同
修饰不同---重载对访问修饰没有特殊要求,重写访问修饰符的限制一定要大于被重写方法的访问修饰符

定义单链表和双链表

1
2
单链表:单链表是最简单的链表形式,每个节点只包含指向下一个节点的指针
双链表:每个节点除了指向下一个节点的指针外,还包含指向前一个节点的指针

指针和引用的区别?

1
2
3
4
5
6
7
8
9
1,引用访问一个变量是直接访问,而指针是间接访问。

2,引用是一个变量的别名,本身不单独分配自己的内存空间,而指针有自己的内存空间。

4,不存在指向空值的引用,但是存在指向空值的指针。

备注:C语言没有引用啊,C++才有

5,引用是类型安全的,指针不是

结构体和类的区别

1
2
3
4
5
6
7
8
9
结构体和类的主要区别在于类型、构造函数、内存分配、继承性、访问控制属性等方面。

类型。结构体是值类型,而类是引用类型。
构造函数。结构体中只能有两个构造函数,一个是默认的无参的构造函数,另一个是全参数的构造函数,而类中可以有多个构造函数。
内存分配。结构体使用栈存储,而类使用堆存储。
继承性。结构体不能继承于类,类也不能继承于结构体,但它们都可以继承于接口。
访问控制属性。结构体默认成员是Public,而类默认成员是Private。


要调用另一个头文件的函数怎么弄

1
2
1. 直接添加用extern声明要调用的全局变量、函数的语句即可
2. include

指针占几个字节

1
2
32位体系结构中,指针通常是4个字节
64位体系结构中,指针通常是8个字节

纯虚函数和虚函数的区别

1
2
3
4
5
1、纯虚函数只有定义,没有实现;而虚函数既有定义,也有实现的代码。
2、包含纯虚函数的类不能定义其对象,而包含虚函数的则可以。

虚函数主要作用是“运行时多态”,父类中提供虚函数的实现,为子类提供默认的函数实现。

纯虚函数以啥结尾

1
虚函数的声明通常会在函数原型前加上 `virtual` 关键字,而纯虚函数的声明除了需要加上 `virtual` 关键字外,还会在函数原型后加上 `=0` 来表示这是一个纯虚函数

怎么用指针p表示二维数组的第三个元素

1
p=*(a)+2

枚举和共同体

1
2
3
4
5
6
7
8
9
10
11
共同体
1. 共同体能够存储不同的数据类型, 但是在同一时间只能存储其中一种类型。
共同体占用的内存大小是其内部最大的成员占用内存大小
全部的成员使用同一块内存
共同体中的值为最后被赋值的那个成员的值
可以在定义共同体的时候创建共同体变量,也可以嵌入结构体中。


枚举顾名思义就是一一列举,把可能的取值一一列举。
1.用枚举创建的变量取值只能在枚举量范围内。
2.枚举的作用域与变量的作用域相同

协议

IIC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
是 PHILIPS 公司推出的芯片间 串行传输总线 
它以 1 根串行数据线(SDA)和 1 根串行时钟线(SCL)实 现了双工的同步数据传输。
IIC 通常有 SDA 数据和 SCL 时钟两个信号。

(1) 特点:同步半双工;高位在前、低位在后,即大端模式。
(2) 连接方式:双线连接,同名端总线连接。连接设备数量受总线最大电容的限制。

写数据步骤:
① 主机发起一个启动信号(START)。
② 主机发送 7bit 从机地址+1bit 读写选择位,1 表示读、0 表示写。
③ 从机产生应答信号(ACK)。
④ 主机发送 8bit 从机寄存器地址。
⑤ 从机产生应答信号(ACK)。
⑥ 主机发送一个字节数据。
⑦ 从机产生应答信号(ACK)。
⑧ 主机发送一个停止信号(STOP)。

读数据步骤:
① 主机发送一个启动信号(START)。
② 主机发送 7bit 从机地址+1bit 读写选择位,1 表示读、0 表示写。
③ 从机产生一个应答信号(ACK)。
④ 主机发送 8bit 从机寄存器地址。
⑤ 从机产生一个应答信号。
⑥ 主机再次发送一个启动信号(START)。
⑦ 主机再次发送 7bit 从机地址+1bit 读写选择位,1 表示读、0 表示写。
⑧ 从机产生一个应答信号(START)。
⑨ 主机读取一个字节数据。
⑩ 主机产生一个非应答信号(NACK)。之后产生一个停止信号(STOP)。

SPI

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
是 Motorola 公司推出的一种同步串行通讯方式,是一种三线同步总线
SPI 通常有 SCK 时钟,STB 片选,DATA 数据信号三个信号。
SPI 总线真正实现了全双工数据传输,SPI 有 3 线跟 4 线两种,4 线的话,就是多了一条叫 SDC 的线,用来告知从设备现在传输的是数据还是指令。
如果要可以实现全双工,也是需要多加一根数据线(MOSI MISO)。
spi 总线特点:
1. 采用主-从模式(Master-Slave) 的控制方式
2. 采用同步方式(Synchronous)传输数据
3. SPI 设备间的数据传输被称为数据交换


SPI(Serial Peripheral Interface)总线协议是一种同步双全工的串行通信协议,用于在集成电路之间进行数据传输。SPI总线通常由一个主设备和多个从设备组成,每个从设备都有一个单独的片选信号,具有以下特点:
-高速传输:SPI总线具有高速传输的特点,通信速率可达几十MHz
-硬件简单:SPI总线只需要少量线路即可完成通信,可以通过硬件实现
-可靠性高:SPI总线采用同步传输方式,数据传输可靠

(1) 特点:同步全双工;按高位在前、低位在后传输,即大端模式。
(2) 连接方式:四线连接,非同名端连接。

(3)四种操作时序:SPI 的时钟极性 CPOL 和时钟相位 CPHA 可以分别为 0 或 1,由此构成了四种组合。
①CPOL = 0,CPHA = 0:空闲时 SCLK 为低电平,在第一个边沿开始采样。
②CPOL = 0,CPHA = 1:空闲时 SCLK 为低电平,在第二个边沿开始采样。
③CPOL = 1,CPHA = 0:空闲时 SCLK 为高电平,在第一个边沿开始采样。
④CPOL = 1,CPHA = 1:空闲时 SCLK 为高电平,在第二个边沿开始采样。

I2C 和 SPI 的区别

1
2
3
4
5
6
1 iic 总线不是全双工,2 根线 SCL SDA。spi 总线实现全双工,4 根线 SCK CS MOSI MISO 
2 iic 总线是多主机总线,通过 SDA 上的地址信息来锁定从设备。spi 总线只有一个主设备,主设备通过 CS 片选来确定从设备
3 iic 总线传输速度在 100kbps-4Mbps。spi 总线传输速度更快,可以达到 30MHZ 以上。
4 iic 总线空闲状态下 SDA SCL 都是高电平。spi 总线空闲状态 MOSI MISO 也都是 SCK 是有 CPOL 决定的
6 iic 总线是 SCL 高电平采样。spi 总线因为是全双工,因此是沿采样,具体要根据 CPHA 决定。一般情况下 master device 是 SCK 的上升沿发送,下降沿采集
8 iic 总线和 spi 总线时钟都是由主设备产生,并且只在数据传输时发出时钟

网络

TCP通信建立和释放的过程?端口的作用?

1
2
1)	连接是三次握手,释放是四次挥手。
2) 端口是一个软件结构,被客户进程或服务进程用来发送和接收信息。一个端口对应一个16比特的数。服务进程通常使用一个固定的端口。

IP地址的编码分为哪两部分?

1
IP地址由两部分组成,网络号和主机号。

TCP、UDP的区别?

1
2
3
4
5
6
1)	TCP是面向连接的,UDP是面向无连接的。
2) TCP是面向字节流的,UDP是基于数据报的。
3) TCP提供可靠服务(正确性、顺序性),UDP提供不可靠服务。
4) TCP程序结构复杂,占用资源多;UDP程序结构简单,占用资源少。
5) TCP有拥塞控制;UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低,适合于实时应用,如IP电话、实时视频会议。
6) TCP只支持一对一;UDP支持一对一、一对多、多对一、多对多。

说说为什么是三次握手的和四次挥手

1
2
3
首先他当然可以设置为更多次数的握手或挥手,每一次的握手、挥手都是传输数据的一个方式,但是他这样会导致更多的资源浪费或更多的开销,这样是并不划算的,所有是要在可行的情况下尽量少的去进行握手和挥手的次数
三次握手就是为保证通信双方的一个接收能力和发送能力,我打个比方,比如:我跟你打电话,我说喂你听得见吗?就相当于一次握手,然后你说我能听见,就确保了我的发送能力和你的接收能力,然后你同时再说一句你有听见吗,我回我能听见,就保证了你的发送能力和我的接受能力,这样的话一共就是3次握手(相当于我发了一个SYN给你然后你回了一个ACK+SYN,这个过程相当于你听到我说你听得到吗,你说我听得到你听得到吗,这两句话其实是在同一时该去说的,所以可以合并为一次握手)
四次挥手,他相当于是我要和你说断开连接,并且你也要和我说断开连接,然后断开连接的请示都是在我们的应用层的代码执行块里面去执行的,然后他的ACK的一个返回,他是在内核态里面去执行的,所以并不能保证我的FIN这个断开连接的请示和ACK是同时发送的,所以他就是一个四次挥手的过程

TCP、UDP的区别?

1
2
3
4
5
6
1)	TCP是面向连接的,UDP是面向无连接的。
2) TCP是面向字节流的,UDP是基于数据报的。
3) TCP提供可靠服务(正确性、顺序性),UDP提供不可靠服务。
4) TCP程序结构复杂,占用资源多;UDP程序结构简单,占用资源少。
5) TCP有拥塞控制;UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低,适合于实时应用,如IP电话、实时视频会议。
6) TCP只支持一对一;UDP支持一对一、一对多、多对一、多对多。

TCP为什么是可靠连接?

1
因为TCP传输的数据满足四大条件:不出错、不丢失、不重复、不乱序,而且拥有窗口机制、拥塞控制机制来提高传输效率。

OSI七层 TCP/IP四层

1
2
3
4
5
1)	七层划分为:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层。

2) 五层划分为:应用层、传输层、网络层、数据链路层、物理层
3) 四层划分为:应用层、传输层、网络层、网络接口层(物理层)

应用层Telnet(远程登录服务)、FTP(文件传输,使用TCP)、SMTP(建立于FTP上的邮件服务)、DNS(域名与IP地址相互转换)HTTP(超文本传输协议)、HTTPS(超文本传输安全协议)等
传输层UDP(无连接、不可靠)、TCP(面向连接、可靠传输)
网络层IP(为主机提供一种无连接、不可靠、尽力而为的数据服务)、ICMP(主机与路由器之间传递控制信息)、IGMP(主机与路由器之间进行组播成员信息交互)
网络接口层(物理层)ARP(IP 地址-> MAC地址)、RARP(MAC地址 -> IP地址)等

从在浏览器地址栏中输入baidu.com到看到百度首页,都涉及到哪些网络协议?

1
2
3
4
5
6
7
TCP/IP五层模型中网络层及以上用到的协议:

1.应用层:HTTP、DNS、HTTPS

2.传输层:TCP、UDP

3.网络层:IP、ARP

单片机

请问51单片机如何模拟I2C总线通信?

1
总线的初始化、启动信号、应答信号、停止信号、写一个字节、读一个字节。

GPIO口一般有哪三个寄存器?

1
控制寄存器、数据寄存器、上拉寄存器。

GPIO的输入输出模式有哪些?

1
2
(1)	输入模式:浮空输入、带上拉输入、带下拉输入、模拟输入。
(2) 输出模式:开漏输出、推挽输出、开漏复用输出、推挽复用输出。

其他

Freertos 和 linux 异同

1
2
3
4
答:FreeRTOS 和 Linux 是两个不同的嵌入式操作系统,它们在设计理念、架构和功能上存在一些异同。
设计理念:FreeRTOS 是一个实时操作系统(RTOS),专注于实时性和资源占用的最小化。而 Linux 是一个通用的操作系统,注重功能丰富性和多任务处理能力。
架构:FreeRTOS 采用了基于优先级的抢占式调度算法,它通常以任务为单位进行调度。而Linux 采用了时间片轮转调度算法,支持多线程和多进程并发执行。
功能:FreeRTOS 提供了基本的任务管理、内存管理等功能,它适用于对实时性要求较高的应用场景,如工业控制、汽车电子等。而 Linux 提供了更为完善的文件系统、网络协议栈等功能,适用于大规模软件开发的应用领域。

信号量

1
2
3
一个可以计数数据结构,由内核实现两个原子操作 wait,signal,需要使用信号量时用系统调用 wait,signal 这两原子操作即可。(信号量是为了解决同步问题,信号量的操作只应该由内核去进行,需要进入内核,所以速度很慢,这是信号量的一个很大缺点)
互斥量:
只有两个状态的信号量(0 和 1)以实现临界区的互斥访问 (信号量只是互斥量的一种实现方式) 互斥量可以在用户空间通过 TSL 或 XCHG 指令(一条指令是不会被打断的)实现,而不需要系统调用(陷入内核)来实现。

条件变量

1
pthread 提供的一种同步机制(利用互斥量,作用有点类似信号量,但不是) 互斥量允许或阻塞对临界区的访问,条件变量则允许线程由于一些未达到的条件而阻塞。这两者经常结合使用。

DMA

1
DMA 用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须 CPU的干预,通过 DMA 数据可以快速地移动。这就节省了 CPU 的资源来做其他操作。

静态库、动态库

1
2
3
4
5
6
1.	静态库在程序编译时会被连接到目标代码中。
优点:程序运行时将不再需要该静态库;运行时无需加载库,运行速度更快
缺点:静态库中的代码复制到了程序中,因此体积较大;静态库升级后,程序需要重新编译链接
2. 动态库是在程序运行时才被载入代码中。
优点:程序在执行时加载动态库,代码体积小;将一些程序升级变得简单;不同的应用程序如果 调用相同的库,那么在内存里只需要有一份该共享库的实例。
缺点:运行时还需要动态库的存在,移植性较差

主观题

1.团队

1
我认为一个高效的团队首先应该是分工明确的,就是大家一起开会讨论项目的预期目标并且进行分工,之后大家就着手实施自己负责的部分,朝着自己的目标迈进。第二就是应该定期沟通,比如说规定三天或者一个星期开一个短会,大家各自阐述进展以及遇到的问题,还有接下来的安排,同时其他人可以给出意见。通过这样明确的分工以及定期的沟通,能够达到比较高的工作效率。

2.职业规划

1
首先我很确定自己对于技术是非常热爱甚至崇拜的,因为技术能实实在在地让我们的生活变得更美好,并且在实现预期的技术目标之后会有很大的成就感。因此我打算走技术路线,不断地探索和学习,一步步成为技术专家。

3.优点

1
2
在工作或者学习上,我认为我有很强的自我驱动能力,一旦明确了自己的目标,即使实现的过程屡受挫折,我也会不断调整自己的精神状态,以积极的一面重新投入,直到目标实现。
在生活上,我是一个生活比较有规律的人,在特定的时间段干特定的事情,比如说早上、下午、晚上一般都是学习时间,然后中午会休息一段时间,傍晚五六点就是练吉他、运动、吃饭的时间,劳逸结合,让我感觉生活质量比较高。

4.缺点

1
2
在工作或者学习上,我觉得我有时候容易钻牛角尖,对一两个不是那么重要的问题深究到底,浪费了一些时间,不过这也是在时间足够情况下才会发生的。
在生活上,与人交往的过程中,我觉得我不够幽默风趣,这一点是我比较想提升的。

5.难忘的事情

1
大学期间我比较难忘的事情就是跟自己团队的小伙伴,经常在实验室做项目做到一两点,甚至有一次为了第二天的比赛还通宵了,我觉得这是比较可贵以及难忘的经历。

6.我是一个怎样的人

1
我认为我是一个比较独立、自信的人,遇到问题一般都是自己独立解决,比较少求助别人,不过在迫不得已的情况下我还是会向别人求助,与人沟通,寻求解决方案。但是一般别人向我求助我都会乐于帮助,在不违背原则的情况下尽力而为,比如说问我要课后作业之类的我一般都会给,但如果说要我跟他配合考试作弊的话那就是不可能的。

7.我喜欢什么样的人

1
我喜欢乐于沟通、乐于分享的人,并且做错了事情能够承认错误,并积极改正。

8.我讨厌什么样的人

1
我讨厌抗拒沟通、固执己见的人,并且做错事情常常碍于面子或者其 他原因不愿承认并改正。

9.团队里有我不喜欢的人怎么办

1
如果不幸团队里有这样的人,那么我在工作上还是会尽力 与他合作,尽力与他沟通,在出现较大问题时就向领导反映。但在私下的生活上我应该不会跟他有太多来往。

10.如何测试自己的项目以确保其达到预期功能的

1
测试一般分为黑盒测试跟白盒测试,黑盒测试就是对系统的各项功能进行测试,白盒测试就是对系统的各个函数进行测试。那么我们在项目的开发过程中,一般两者都会用到,在初步测试各部分软件的时候,会用白盒测试,就是测试各个函数的接口;在系统集成之后的联合调试中,会用黑盒测试,就是测试系统的各项功能是否符合预期目标。

11.有没有当过负责人以及如何当好一个负责人

1
我在一个四人参与的项目中担任过负责人。我认为要当好一个负责人首先要积极主动地面对问题,跟小组成员相互督促;然后组织项目成员定期开会,讨论项目的预期目标、具体分工、如何克服遇到的问题等等这些细节,同时可能还需要定时向老师汇报项目进展;最后组织项目成员做好项目的收尾工作。

12.如何理解嵌入式系统

1
我认为嵌入式系统是一个“基于特定的应用场景 来深度定制软硬件资源的 计算机系统”。

13.过去的学习经历以及接下来的学习计划

1
今年以来我系统地学习了嵌入式软件所需要的专业知识,建立了较为完善的知识体系,接下来打算在毕业设计时候做一个关于嵌入式的应用并不断地完善自己的知识体系。

14.为什么认为这个岗位适合你

1
一开始我做了好几个单片机的项目,对这方面了解得比较多,因此比较感兴趣。后来又学习了嵌入式 Linux,觉得嵌入式 Linux 更加高级,因此不满足于单片机的学习,决定往嵌入式深入发展。最后通过不断学习建立了较为完善的知识体系,决定毕业之后从事嵌入式软件开发工作。我了解到贵公司的这个岗位是做嵌入式系统软件开发的,跟我的就业方向一致。

15.最有成就感的事情

1
我认为大学生涯最有成就感的事情就是没有虚度时光,合理地规划自己的大学生活,让自己的课内学习、课外实践、学生工作、个人兴趣、人际交往都得到了发展。