1.
堆、栈、队列、局部变量、全局变量、static、extern(都是问区别是什么,内存空间多少,作用是什么等等)答:
(1)全局变量使用范围在本程序范围,若要在其他程序中也能使用,则在其他程序中用extern声明,声明时不能漏掉变量类型。
(2)局部变量只能在本函数使用,本函数一调用完毕,释放栈空间,销毁变量。
(3)static修饰函数后,就限定了该函数只在本文件可见,其他文件不能引用。用来定义变量也是一样的。
(4)用extern声明函数后就可在另外的文件使用这一函数,用来定义变量也是一样的。
(5)栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。
(6)堆区(heap)— 由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收。
(7)队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。
2. 宏定义(有参)
(1) 有参:定义个宏MIN(a,b),输入两个参数,输出较小值。
答:
#include #define MIN(a,b) a int main(void) { printf("%dn",MIN(100,20)); } |
(2) #define type struct*和typedef struct* type哪个更加好?
答:typedef struct* type更加好。因为是针对类型定义。
扩展—它们之间的区别:
① 关键字typedef在编译阶段有效,由于是在编译阶段,因此typedef有类型检查的功能。
② #define则是宏定义,发生在预处理阶段,也就是编译之前,它只进行简单而机械的字符串替换,而不进行任何检查。
3. (1)冒泡排序
答:
#include #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) void mp_sort(int * p, int n); int main(int argc,char** argv) { int i; int data[]={10,100,20,40,90,120,56}; mp_sort(data,ARRAY_SIZE(data)); for(i=0;i { printf("%dn",data); } } void mp_sort(int * p, int n) { int i, j; int temp; for(i = 0; i < n-1; i++) { for(j = 0; j< n-1-i; j++) { if(p[j] > p[j+1]) { temp = p[j]; p[j] = p[j+1]; p[j+1] = temp; } } } } |
(2)一个int整数,算出其二进制有几个1?
答:
#include int main(int argc,char** argv) { int i,count=0; i=100; do { if((i%2)!=0)//判断末尾是否为1 { count++;//末尾为1则count++ } i=i/2;//i除2,相当于右移一位 }while(i>=1); printf("count=%dn",count); //输出结果 } |
(3)int a,b,c; c=a+++b;这段代码是用来做什么的?
答:计算a+b的和。c的结果等于a+b的和。
4. 中断是嵌入式系统中重要的组成部分,这导致了很多编译开发商提供一种扩展—让标准C支持中断。具代表事实是,产生了一个新的关键字 __interrupt。下面的代码就使用了__interrupt关键字去定义了一个中断服务子程序(ISR),请评论一下这段代码的。
__interrupt double compute_area (double radius)
{
double area = PI * radius * radius;
printf("nArea = %f", area);
return area;
}
答:中断服务函数没有返回值。
5. 嵌入式系统经常具有要求程序员去访问某特定的内存位置的特点。在某工程中,要求设置一绝对地址为0x67a9的整型变量的值为0xaa66。编译器是一个纯粹的ANSI编译器。写代码去完成这一任务。
答:
int *p=(int *)0x67a9; *p=0xaa66; |
6. 单向链表,递归调用(简单题)
答:
(1) 链表创建
#include #include typedef struct str { int a; struct str *netx; //下一个节点 }STR; STR* start_str(void);//链表申请节点 void print(STR* p); //打印节点数据--遍历节点 int main(void) { int a; STR *b; b=start_str(); print(b); return 0; } //遍历节点 void print(STR* p) { while(p->netx!=NULL) //遍历节点 { printf("%dn",p->a); p=p->netx; } } //链表申请节点 STR* start_str(void) { int tmp; STR *head,*p,*end; //head表示表头 p表示中间节点 end表示表尾 head=(STR*)malloc(sizeof(STR)); //表头申请空间 if(head==NULL) { printf("空间申请错误!!n"); return (STR*)0; } head->a=0; //数据为空 end=head; //表位指向表头 end->netx=NULL; //表尾指向空 while(1) { p=(STR*)malloc(sizeof(STR)); if(p==NULL) { printf("空间申请错误n"); break; } scanf("%d",&tmp); //获取键盘值 if(tmp==0)break; p->a=tmp; //给新节点赋值 end->netx=p; //表尾指向新节点节点 end=p; //赋值给新节点 end->netx=NULL; //表尾指向空 } return head; } |
(2) 递归调用
#include void function_1(void); //函数 int main(void) { function_1(); //掉用函数 return 0; } void function_1(void) { static int cnt=0; cnt++; printf("调用次数:%dn",cnt); if(cnt>=10) { return; } else { function_1(); } } |
7. 内核空间与用户空间的区别?他们之间的通讯?
答: (1) 内核空间与用户空间的区别: Linux简化了分段机制,使得虚拟地址与线性地址总是一致,因此,Linux的虚拟地址空间也为0~4G。Linux内核将这4G字节的空间分为两部分。将最高的1G字节(从虚拟地址0xC0000000到0xFFFFFFFF),供内核使用,称为“内核空间”。而将较低的3G字节(从虚拟地址 0x00000000到0xBFFFFFFF),供各个进程使用,称为“用户空间)。因为每个进程可以通过系统调用进入内核,因此,Linux内核由系统内的所有进程共享。于是,从具体进程的角度来看,每个进程可以拥有4G字节的虚拟空间。
(2) 内核空间和用户空间之间如何进行通讯?
8. 线程与线程、进程与进程之间的通讯机制?
答:
(1)进程间通信机制:文件映射、共享内存、匿名管道、命名管道、Sockets
(2)线程间通信机制:信号量、互斥量、临界区、全局变量
9. uboot的启动流程?
答:U-Boot启动内核的过程可以分为两个阶段,两个阶段的功能如下:
(1)第一阶段的功能
① 硬件设备初始化
② 加载U-Boot第二阶段代码到RAM空间
③ 设置好栈
④ 跳转到第二阶段代码入口
(2)第二阶段的功能
① 初始化本阶段使用的硬件设备
② 检测系统内存映射
③ 将内核从Flash读取到RAM中
④ 为内核设置启动参数
⑤ 调用内核
10. 说几个你了解的文件系统,说说它们的特点和使用场合?
答:
(1) FatFs文件系统:FatFs是一个通用的文件系统模块,用于在小型嵌入式系统中实现FAT
文件系统。 FatFs 的编写遵循ANSI C
,因此不依赖于硬件平台。它可以嵌入到便宜的微控制器中,如 8051, PIC, AVR, SH, Z80, H8,
ARM 等等,不需要做任何修改。
(2) Ext2、ext3、ext4
11. 触摸屏的硬件工作原理
答:
按照触摸屏的工作原理和传输信息的介质而言,我们把触摸屏分为4种:电阻式,电容式,红外线式和表面声波式。电阻式触摸屏利用压力感应进行控制,包含上下叠合的两个透明层,通常还要用一种弹性材料来将两层隔开。在触摸某点时,两层会在此点接通。四线和八线触摸屏由两层具有相同表面电阻的透明材料组成,五线和七线触摸屏由一个阻性层和一个导电层组成。
电阻式触摸屏原理:触摸屏包含上下叠合的两个透明层,四线和八线触摸屏由两层具有相同表面电阻的透明阻性材料组成,五线和七线触摸屏由一个阻性层和一个导电层组成,通常还要用一种弹性材料来将两层隔开。当触摸屏表面受到的压力(如通过笔尖或手指进行按压)足够大时,顶层与底层之间会产生接触。所有的电阻式触摸屏都采用分压器原理来产生代表X坐标和Y坐标的电压。分压器是通过将两个电阻进行串联来实现的。上面的电阻(R1)连接正参考电压(VREF),下面的电阻(R2)接地。两个电阻连接点处的电压测量值与下面那个电阻的阻值成正比。为了在电阻式触摸屏上的特定方向测量一个坐标,需要对一个阻性层进行偏置:将它的一边接VREF,另一边接地。同时,将未偏置的那一层连接到一个ADC的高阻抗输入端。当触摸屏上的压力足够大,使两层之间发生接触时,电阻性表面被分隔为两个电阻。它们的阻值与触摸点到偏置边缘的距离成正比。触摸点与接地边之间的电阻相当于分压器中下面的那个电阻。因此,在未偏置层上测得的电压与触摸点到接地边之间的距离成正比。
12. iic的时序图
13.M4 lcd屏的接口、通讯协议。
答:
8080时序与6800时序读写的控制,采用不同的方式:
8080是通过“读使能(RE)”和“写使能(WE)”两条控制线进行读写操作
6800是通过“总使能(E)”和“读写选择(W/R)”两条控制线进行
很多MCU或者LCD模块外部接口一般采用并行方式,并行接口接口线的读写时序常见以下两种模式:
(1) 8080模式通常有下列接口信号:
/RES(复位线),DB0~DB7(双向数据线),D/I(数据/指令选择线,1:数据读写,0:命令读写),CS(片选信号线,如果有多片组合,可有多条片选信号线),/WR(MPU向LCD写入数据控制线),/RD(MPU从LCD读入数据控制线);
(2) 6800模式下,/RES、DB0~DB7、D/I的功能同模式(1),其他信号线为:R/W读写控制(1:MPU读, 0:MPU写)。
E,允许信号(多片组合时,可有多条允许信号线)。
M68是摩托罗拉的标准接口,I80是英特尔的标准接口,其中差别在控制信号!
M6800: /CS, RS, R/(/W), E
I8080: /CS, RS, /WR, /RD
答:socket网络编程(FTP、NFS)、串口
15. 用shell删除/a/b/c里的文件。 Makefile怎么写。
答:rm /a/b/c/* -f
16. 简单说一下按键输入?(过程、简要代码、有几种方法)
答:定时器轮询、中断检测
17. 怎么创建线程、进程。(找LINUX工作基本会问到)
答:
创建线程:
void *start_pthread(void *arg) { while(1); } int main(int argc,char **argv) { //定义线程的ID pthread_t pthid; //创建线程 pthread_create(&pthid,NULL,start_pthread,NULL); while(1); return 0; } |
创建进程:
#include #include #include int main(void) { pid_t pid; if(fork()==0) //判断是否是子进程 { printf("子进程的 PID: %dn",getpid()); } else { printf("父进程的 PID: %dn",getpid()); } } |
18. 把摄像头采集到的YUV图片数据保存成JPG图发送效率比较低?
答:可以搭建流媒体服务器。使用FFMPEG库实现。
19. TCP/IP网络编程的相关问题?(找LINUX工作基本会问到)
答:TCP/IP不是TCP和IP这两个协议的合称,而是指因特网整个TCP/IP协议族。
从协议分层模型方面来讲,TCP/IP由四个层次组成:网络接口层、网络层、传输层、应用层。
TCP/IP主要特点:
(1)TCP/IP协议不依赖于任何特定的计算机硬件或操作系统,提供开放的协议标准,即使不考虑Internet,TCP/IP协议也获得了广泛的支持。所以TCP/IP协议成为一种联合各种硬件和软件的实用系统。
(2)TCP/IP协议并不依赖于特定的网络传输硬件,所以TCP/IP协议能够集成各种各样的网络。用户能够使用以太网(Ethernet)、令牌环网(Token Ring Network)、拨号线路(Dial-up line)、X.25网以及所有的网络传输硬件。
(3)统一的网络地址分配方案,使得整个TCP/IP设备在网中都具有惟一的地址
(4)标准化的高层协议,可以提供多种可靠的用户服务。