嵌入式面试题
Posted kunx
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了嵌入式面试题相关的知识,希望对你有一定的参考价值。
来自互联网,2020整理
1、
int a[10]={1,2,3,4,5,6,7,8,9,0}; int *p=&a[1]; 则p[6]等于?
答:8;这个还是很好理解的p[0]=2嘛
2、整数数组清零的函数有?
#include <strings.h> void bzero(void *s, size_t n); void * memset ( void * ptr, int value, size_t num );
3、sizeof();的作用
功能是返回一个变量或者类型的大小(以字节为单位);
4、考查指针
main() { char* str[] = { "ab","cd","ef","gh","ij","kl" }; char* t; t = (str + 4)[-1]; printf("%s", t); } 结果是?
答:
gh;用第1题的思想
5、例如:int a=0x12345678;(a首地址为0x2000),问大端怎么存储?
答:
小端:低位字节数据存储在低地址 大端:高位字节数据存储在低地址 0x2000 0x2001 0x2002 0x2003 0x12 0x34 0x56 0x78 大端格式
6、异步IO和同步IO区别?
如果是同步IO,当一个IO操作执行时,应用程序必须等待,直到此IO执行完,相反,
异步IO操作在后台运行,IO操作和应用程序可以同时运行,提高系统性能,提高IO流量;
在同步文件IO中,线程启动一个IO操作然后就立即进入等待状态,直到IO操作完成后才醒来继续执行,
而异步文件IO中,线程发送一个IO请求到内核,然后继续处理其他事情,内核完成IO请求后,将会通知线程IO操作完成了。
7、返回什么?
int foo(void) { int i; char c = 0x80; //1000 0000-取反+1 是 11000 0000=-128 i = c; if (i > 0) return 1; return 2; }
答:返回值为2;因为i=c=-128;如果c=0x7f,则i=c=127。
8、效率最高的算法
a = b * 2; a = b / 4; a = b % 8; a = b / 8 * 8 + b % 4; a = b * 15;
答
a = b * 2->a = b << 1; a = b / 4->a = b >> 2; a = b % 8->a = b & 7; a = b / 8 * 8 + b % 4->a = ((b >> 3) << 3) + (b & 3) a = b * 15->a = (b << 4) - b
9、c关键字有?
c的关键字共32个 *数据类型关键字(12) char,short,int,long,float,double,unsigned,signed,union,enum,void,struct *控制语句关键字(12) if,else,switch,case,default,for,do,while,break,continue,goto,return *存储类关键字(5) auto,extern,register,static,const *其他关键字(3) sizeof,typedef,volatile
10、返回什么
int main(void) { unsigned int a = 6; int b = -20; char c; (a + b > 6) ? (c = 1) : (c = 0); }
答:c=1,
a+b=-14;如果a为int类型则c=0。
原来有符号数和无符号数进行比较运算时(==,<,>,<=,>=),有符号数隐式转换成了无符号数(即底层的补码不变,但是此数从有符号数变成了无符号数),
比如上面 (a+b)>6这个比较运算,a+b=-14,-14的补码为1111111111110010。此数进行比较运算时,
被当成了无符号数,它远远大于6,所以得到上述结果。
插入一个和此题无关知识点:所谓的函数是可重入的(也可以说是可预测的);宏定义是在预编译阶段被处理的
11、
输出什么
int main() { int j = 2; int i = 1; if (i = 1) j = 3; if (i = 2) j = 5; printf("%d", j); }
输出为5;如果再加上if(i=3)j=6;则输出6。
12、Norflash与Nandflash的区别
(1)、NAND闪存的容量比较大
(2)、由于NandFlash没有挂接在地址总线上,所以如果想用NandFlash作为系统的启动盘,就需要CPU具备特殊的功能,
如s3c2410在被选择为NandFlash启动方式时会在上电时自动读取NandFlash的4k数据到地址0的SRAM中。
(3)、NAND Flash一般地址线和数据线共用,对读写速度有一定影响。NOR Flash闪存数据线和地址线分开,
所以相对而言读写速度快一些。
反码:对原码除符号位外的其余各位逐位取反就是反码
补码:负数的补码就是对反码加1
正数的原码、反码、补码都一样
13、内存管理MMU的作用
*内存分配和回收
*内存保护
*内存扩充
*地址映射
14、printf可以接受多个参数,为什么,请写出printf的原型。
int printf ( const char * format, ... );
15、位转换,如1000 0000输出0000 0001
unsigned char bit_reverse(unsigned char c) { unsigned char buf = 0; int bit = 8; while (bit) { bit--; buf |= ((c & 1) << bit); c >>= 1; } return buf; }
16、字符串倒序
void inverted_order(char* p) { char* s1, * s2, tem; s1 = p; s2 = s1 + strlen(p) - 1; while (s1 < s2) { tem = *s1; *s1 = *s2; *s2 = tem; s1++; s2--; } }
17、引用和指针的区别
(1). 指针是一个实体,而引用仅是个别名; (2). 引用使用时无需解引用(*),指针需要解引用; (3). 引用只能在定义时被初始化一次,之后不可变;指针可变; (4). 引用没有 const,指针有 const,const 的指针不可变; (5). 引用不能为空,指针可以为空; (6). “sizeof 引用”得到的是所指向的变量(对象)的大小, 而“sizeof指针”得到的是指针本身(所指向的变量或对象的地址)的大小; (7). 指针和引用的自增(++)运算意义不一样;
18、队列和栈的区别
队列是先进先出,只能在一端插入另一端删除,可以从头或尾进行遍历(但不能同时遍历),
栈是先进后出,只能在同一端插入和删除,只能从头部取数据
19、TCP通信建立和结束的过程?端口的作用
三次握手和四次挥手;
端口是一个软件结构,被客户程序或服务进程用来发送和接收信息。
一个端口对应一个16比特的数。服务进程通常使用一个固定的端口。
21端口:21端口主要用于FTP(File Transfer Protocol,文件传输协议)服务。
20、物理地址转换成IP地址的协议?反之?
地址解析协议(ARP)的作用是将IP地址转换成物理地址;
反地址解析协议(RARP)则负责将物理地址转换成IP地址。
21、全局变量和局部变量的区别。
全局变量,储存在静态区.进入main函数之前就被创建.生命周期为整个源程序;
局部变量,在栈中分配.在函数被调用时才被创建.生命周期为函数内。
22、写一个程序, 要求功能:求出用1,2,5这三个数不同个数组合的和为100的组合个数。
如:100个1是一个组合,5个1加19个5是一个组合。。。。 请用C++语言写。
答案:最容易想到的算法是:
设x是1的个数,y是2的个数,z是5的个数,number是组合数
注意到0<=x<=100,0<=y<=50,0<=z=20,所以可以编程为:
int number = 0; for (int x = 0; x <= 100; x++) for (int y = 0; y <= 50; y++) for (int z = 0; z <= 20; z++) if ((x + 2 * y + 5 * z) == 100) number++;
23、内存对齐问题的原因?
平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据;
性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐,因为为了访问未对齐的内存,处理器需要做两次内存访问,
而对齐的内存访问仅需要一次。
24、比较一下进程和线程的区别?
(1)、调度:线程是CPU调度和分派的基本单位
(2)、拥有资源:
* 进程是系统中程序执行和资源分配的基本单位
* 线程自己一般不拥有资源(除了必不可少的程序计数器,一组寄存器和栈),但他可以去访问其所属进程的资源,
如进程代码,数据段以及系统资源(已打开的文件,I/O设备等)。
(3)系统开销:
* 同一进程中的多个线程可以共享同一地址空间,因此它们之间的同步和通信的实现也比较简单
* 在进程切换的时候,涉及到整个当前进程CPU环境的保存以及新被调度运行的进程的CPU环境的设置;
而线程切换只需要保存和设置少量寄存器的内容,并不涉及存储器管理方面的操作,从而能更有效地使用系统资源和
提高系统吞吐量。
25、请问运行Test函数会有什么样的结果?
char* GetMemory(void) { char p[] = "hello world"; return p; } void Test(void) { char* str = NULL; str = GetMemory(); printf("%s ",str); }
答:可能是乱码。因为GetMemory返回的是指向“栈内存”的指针,该指针的地址不是 NULL,
但其原现的内容已经被清除,新内容不可知。
26、请问运行Test函数会有什么样的结果?
void Test(void) { char* str = (char*)malloc(100); strcpy(str, "hello"); free(str); if (str != NULL) { strcpy(str, "world"); printf("%s ",str); } }
答:篡改动态内存区的内容,后果难以预料,非常危险。因为free(str);之后,str成为野指针,
if(str != NULL)语句不起作用。
野指针不是NULL指针,是指向被释放的或者访问受限内存指针。
造成原因:指针变量没有被初始化任何刚创建的指针不会自动成为NULL;
指针被free或delete之后,没有置NULL;
指针操作超越了变量的作用范围,比如要返回指向栈内存的指针或引用,因为栈内存在函数结束时会被释放。
27、
unsigned char *p=(unsigned char *)0x0801000 unsigned char *q=(unsigned char *)0x0810000
答
p+5 =? 0x0801005 q+5 =? 0x0810005
28、进程间通信方式:管道、命名管道、消息队列、共享内存、信号、信号量、套接字。
(1)、 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。 进程的亲缘关系通常是指父子进程关系。 (2)、有名管道 (named pipe) :有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。 (3)、信号量( semophore ) :信号量是一个计数器,可以用来控制多个进程对共享资源的访问。 它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。 因此,主要作为进程间以及同一进程内不同线程之间的同步手段。 (4)、消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。 消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。 (5)、信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。 (6)、共享内存( shared memory ) :共享内存就是映射一段能被其他进程所访问的内存, 这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制, 如信号两,配合使用,来实现进程间的同步和通信。 (7)、套接字( socket ) : 套接字也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。
29、宏和函数的优缺点?
(1)、函数调用时,先求出实参表达式的值,然后带入形参。而使用带参数的宏只是进行简单的字符替换。 (2)、函数调用是在程序运行时处理的,分配临时的内存单元;而宏展开则是在编译时进行的,在展开时并不分配内存单元, 不进行值的传递处理,也没有“返回值”的概念。 (3)、对函数中的实参和形参都要定义类型,二者的类型要求一致,应进行类型转换;而宏不存在类型问题,宏名无类型, 它的参数也是无类型,只是一个符号代表,展开时带入指定的字符即可。宏定义时,字符串可以是任何类型的数据。 (4)、调用函数只可得到一个返回值,而宏定义可以设法得到几个结果。 (5)、使用宏次数多时,宏展开后源程序长,因为每次展开一次都使程序增长,而函数调用不使源程序变长。 (6)、宏替换不占运行时间,只占编译时间;而函数调用则占运行时间(分配单元、保留现场、值传递、返回)。
30、5["abcdef"]能够编译通过,请问编译后的结果是什么?
printf("%d ",5["abcdef"]);输出‘f‘的ACSII值,如果是4["abcdef"]则输出‘e‘的ACSII的值。
31、下面都输出什么结果
sscanf("123456 ", "%4s", buf); //1234 sscanf("1234576 asdfga", "%[^ ]", buf); //1234576 sscanf("123456aafsdfADDEFFjj", "%[1-9a-z]", buf); //123456aafsdf sscanf("123afsdfADJKLJpp", "%[^A-Z]", buf); //123afsdf
32、数组a[N],存放了1至N-1个数,其中某个数重复一次。写一个函数,找出被重复的数字.时间复杂度必须为o(N)函数原型:
int do_dup(int a[],int N)
int do_dup(int a[], int N) { int* p = (int*)malloc(N * sizeof(int)); for (int j = 0; j < N; j++) { p[j] = 0; } int result; for (int i = 0; i < N; i++) { if (p[a[i]] == 0) { p[a[i]] = a[i]; } else { result = a[i]; cout << "the repeated num is " << result << endl;; return result; } } free(p); return 0; }
33、输出什么
char a = 100; char b = 150;//10010110//01101010 unsigned char c; c = (a < b) ? a : b;
答:c=150
34、在C语言中memcpy和memmove是一样的吗?
memmove()与memcpy()一样都是用来拷贝src所指向内存内容前n个字节到dest所指的地址上,不同是,
当src和dest所指的内存区域重叠时,memmove()仍然可以正确处理,不过执行效率上略慢些。
35、C语言程序代码优化方法
* 选择合适的算法和数据结构
* 使用尽量小的数据类型
* 使用自加、自减指令
* 减少运算的强度
求余运算(a=a%8改为a=a&7)
平方运算(a=pow(a,2.0)改为a=a*a)
用移位实现乘除法运算
* 延时函数的自加改为自减
* switch语句中根据发生频率来进行case排序
36、找出一个字符串中一个最长的连续的数字,并标注出位置和个数。
void main() { char input[100]; char output[100] = { 0 }; int count = 0, maxlen = 0, i = 0; char* in = input, * out = output, * temp = NULL, * final = NULL; printf("Please input string(length under 100): "); scanf("%s", input); printf("Input string is %s ", input); while (*in != ‘