嵌入式软件面试经典问题

一、进程与线程(不同的系统资源管理方式)

1.区别

进程:资源分配的基本单位,由一个或者多个线程组成
线程:调度器进行调度的基本单位,一个任务
每个进程都有自己独立的内存空间,一个进程可以有多个线程,进程切换开销大
多个线程共享内存,线程切换开销小
一个进程崩溃不影响其他进程
一个线程崩溃影响所处的整个进程

2.多进程,多线程优缺点

从内存占用,数据共享,同步,CPU利用率,创建销毁和切换速度,可靠性,编程调试比较

3.进程和线程的选择

创建和销毁频繁选线程
需要大量计算,切换频繁选线程
安全稳定选进程,需要速度选线程

4.多进程,多线程通讯(同步)方法

进程间:有名管道(进程AB)和无名管道(父子进程),消息队列,信号量,共享内存,套接字

5.进程状态转换

就绪,阻塞,运行

6.父进程,子进程

父进程调用fork()函数后,复制出一个子进程,两个进程拥有相同的代码段、数据段和用户堆栈
一般设置父进程等待子进程执行完毕

7.上下文切换

进程上下文切换:当进程进行切换时,对CPU所有寄存器的值,堆栈中的内容以及进程的执行位置进行保存,以便再次执行时恢复切换前状态
中断上下文:由于中断信号产生,当前进程中断,对当前进程的执行现场进行保存,转而去执行中断程序

二、C/C++

1.new和malloc

malloc和free是C++/C的库函数,需要加头文件stdlib.h;new和delete是C++的关键字,不需要加头文件,需要编译器支持
使用new申请内存,无需指定内存块大小,编译器会根据类型信息自行计算;malloc需要写出所需分配内存大小
new分配成功时返回是对象类型指针,无需进行类型转换;malloc返回void指针(只知道地址,不知道长度),需要强制类型转换为需要的类型

2.1GB内存能malloc(1.2G)

有可能,malloc函数是申请了一块虚拟地址空间与物理内存无关,得到的是虚拟空间中的地址,之后程序运行提供的物理内存由操作系统完成

3.extern"C"作用

使C++代码中能调用C语言编写的代码,使编译器按C语言进行编译

4.strcat,strncat,strcmp,strcpy,memcpy哪些函数会导致内存溢出,如何改进

strcat(char* dest,char* src) src指向的字符串追加到dest指向的字符串的尾部
strncat(char* dest,const char* src,size_t n) n表示要追加的最大字符数
strcmp(char)比较两个字符串的大小,一个字符一个字符按ASCLL码比较
strcpy(char *dest, const char *src) 把 src 所指向的字符串复制到 dest 不安全,不做任何检查,不判断拷贝大小,不判断目的地址内存是否够用
strncpy(dest,src,n)
memcpy(void *dest, void *src, unsigned int n) 可以拷贝任意类型数据,n表示要复制的最大字符数
strcat和strcpy容易造成内存溢出

5.static用法

static修饰局部变量,使其存储再静态区,函数执行完这个局部变量不会被释放(当二次调用其函数时不会再定义)
static修饰全局变量,使其只在本文件有效
static修饰函数,使得函数只在本文件有效

6.const用法

const修饰的数据只可读不可修改

7.volatile作用和用法

防止编译器优化,每次用到这个变量就读取内存地址的值,而不是保存在寄存器的值
使用情景:一些设备的硬件寄存器(如状态寄存器),多线程中共享的变量,中断函数供其他程序访问的变量

8.const常量和#define宏的区别

#define max 1 在预处理阶段进行替换,不分配内存,不进行类型安全检查
const int max=1; 在编译时确定其值,分配内存,进行类型安全检查

9.变量的作用域,生命周期

全局变量:作用于所在文件,其他文件也可外部引用;一直到程序结束
局部变量:作用局限于一个函数,进入作用域时生成,离开时消失

10.sizeof和strlen

sizeof()是个运算符,返回一个uint类型表示所使用操作数占空间的字节大小,编译的时候就出结果
strlen()是一个参数为字符型指针(char const*)函数,返回该字符串的长度,使用时需引用头文件<string.h>,运行时才出结果,

int main()  
{   
	char *p = "hello";  
	char arr1 []= "hello";  
	char arr2[] = { 'h', 'e', 'l', 'l', 'o' }; 
	printf("%d\n", sizeof( p)); 
	//结果4,因为指针变量的所占空间大小仅仅和操作系统位数有关32-4,64-8
    printf("%d\n", sizeof(arr1));
	//结果6,字符串默认以\0结尾,sizeof()包含\0的计算
	printf("%d\n", sizeof(arr2));
	//结果为5,因为为字符型表示,并不含有\0(仅仅字符串有\0)
	printf("%d\n", strlen( p));
	//结果为5,strlen求的是字符串的长度,不包含\0
	printf("%d\n", strlen(arr1));
	//结果为5,strlen求的是字符串的长度,不包含\0
	printf("%d\n", strlen(arr2));
	//因为字符型不包含\0,但字符串需要找到\0才可结束,所以在'o'之后继续向后读取直到找到\0,所以是一个随机值 
}   

11.struct和union内存对齐

内存对齐作用:便于cpu访问内存,节省存储空间
struct对齐:
1、结构体变量的首地址和总大小是结构体中最宽数据类型的整数倍。
2、结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍
将相同类型和大数据成员的放前面的成员放在一起,这样就减少了编译器为了对齐而添加的填充字符。
[^如32位的cpu按4的倍数来寻址,第一个成员为char,第二个为int,第三个为char,分配了12个字节的空间]
如果把两个char放前面,则可以节约4个字节的空间
union对齐:
如int b,char a[9]最大数据成员为char a[9] 则一共分配了12个字节的空间
预编译指令#pragma pack(n),所有成员对齐以n字节为准
attribute(packed)取消对齐

12.inline函数

以空间换时间的做法,省去函数调用和返回带来的开销,以代码复制为代价直接展开运行
适用被多次调用的语句较少,没有循环递归的函数,否则编译器可能会优化
声明和定义放一起,分离会导致链接错误

13.内存分区

栈区:编译器分配,函数返回值,局部变量
堆区:自行分配
全局区/静态区:全局变量,静态变量,常数
代码区:二进制代码 (ROM)

14.32位编译情况下,判断所使用机器大小端方法

大端存储:高位存在低地址,低位存在高地址
小端存储:高位存在高地址,地位存在低地址
判断方法:
联合体先从低地址开始存,同一时间只有一个成员占有内存

#include <stdio.h>	
int main() {		
union w{	
	int a;
	char b;
}c;
	c.a=1;
	if(c.b==1)
		printf("xiaoduan\n");
	else
		printf("daduan\n");
	return 0;
}

int强制转换为char,p指向a的低字节

#include <stdio.h>
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值