嵌入式

大疆创新笔试题目

1、判断机器大小端

union 
{
    short s;
    char c[sizeof(short)];
} un;

un.s = 0x0102;
if(sizeof(short) == 2) 
{
    if(un.c[0] == 1 && un.c[1] == 2)
        printf("big-endian\n");
    else if (un.c[0] == 2 && un.c[1] == 1)
        printf("little-endian\n");
    else
        printf("unknown\n");
} else
    printf("sizeof(short)= %d\n",sizeof(short));

2、c函数参数(__cdecl调用方式)、返回值传递方式,调用后如何返回到调用前的下一条指令执行。
参数传递
__cdecl
是C Declaration的缩写(declaration,声明),表示C语言默认的函数调用方法:所有参数从右到左依次入栈,由调用者负责把参数压入栈,最后也是由调用者负责清除栈的内容
__stdcall
是StandardCall的缩写,是C++的标准调用方式:所有参数从右到左依次入栈,由调用者负责把参数压入栈,最后由被调用者负责清除栈的内容

返回值传递
1.对于小于4个字节的数据函数将返回值存储在eax中。
2.5~8个字节对象的情况调用惯例都是采用eax和edx的联合返回方式进行。
3.大于8个字节的返回类型,用一下代码测试:

typedef struct big_thing
{
    char buf[128];
}big_thing;

big_thing return_test()
{
    big_thing b;
    b.buf[] = 0;
    return b;
}

int main()
{
    big_thing n = return_test();
}
首先main函数在栈额外开辟了一片空间,并将这块空间的一部分作为传递返回值的临时对象,这里称为temp
将temp对象的地址作为隐藏参数传递个return_test函数
return_test 函数将数据拷贝给temp对象,并将temp对象的地址用eax传出。
return_test返回以后,mian函数将eax 指向的temp对象的内容拷贝给n。

调用函数分配一块临时空间,将该空间的地址作为隐藏参数传递给被调函数,而后被调函数将数据拷贝到这块临时空间中,并将其地址用eax传出。

如果返回值的类型的尺寸太大,c语言在函数的返回时会使用一个临时的栈上内存作为中转,结果返回值对象会被拷贝两次。因而不到万不得已,不要轻易返回大尺寸对象。
参考:函数返回值传递

函数返回值为什么一般放在寄存器中,这主要是为了支持中断;如果放在堆栈中有可能因为中断而被覆盖。

函数的堆栈帧
栈在程序运行中具有举足轻重的地位。最重要的,栈保存了一个函数调用所需要的维护信息,被称为堆栈帧(Stack Frame),一个函数(被调函数)的堆栈帧一般包括下面几个方面的内容:
(1) 函数参数,默认调用惯例情况下从右向左的顺序依次把参数压入栈中。由函数调用方执行。
(2) 函数的返回地址,即调用方调用此函数(如call func1)的下一条指令的地址。函数调用方(call指令)执行。
(3) 保存调用方函数的EBP寄存器,即将调用方函数的EBP压入堆栈,并令EBP指向此栈中的地址:pushl %ebp; movl %esp, %ebp。由被调函数执行。
(4) 上下文:保存在函数调用过程中需要保持不变的寄存器(函数调用方的),如ebx,esi,edi等。由被调函数执行。
(5) 临时变量,如非静态局部变量

在一个多任务嵌入式系统中,有一个CPU可直接寻址的32位寄存器REGn,地址为 0x1F000010,编写一个安全的函数,将寄存器REGn的指定位反转(要求保持其他bit的值不变)

二.嵌入式基本知识
1. 简述处理器中断处理的过程(中断向量、中断保护现场、中断嵌套、中断返回等)。(总 分10分)
2. 简述处理器在读内存的过程中,CPU核、cache、MMU如何协同工作?画出CPU核、 cache、MMU、内存之间的关系示意图加以说明(可以以你熟悉的处理器为例)。(总分10分)

三.基本通信知识
1. 请说明总线接口USRT、I2C、USB的异同点(串/并、速度、全/半双工、总线拓扑等)。 (总分5分)
2. 列举你所知道的linux内核态和用户态之间的通信方式并给出你认为效率最高的方式, 说明理由。(总分5分)

四.系统设计
有一个使用UART进行通信的子系统X,其中UART0进行数据包接收和回复,UART1进行数据包转发。子系统X的通信模块职责是从UART0接收数据包,如果为本地数据包(receiver为子系统X),则解析数据包中的命令码(2字节)和数据域(0~128字节),根据命令码调用内部的处理程序,并将处理结果通过UART0回复给发送端,如果非本地数据包,则通过UART1转发。
如果由你来设计子系统X的通信模块:
1) 请设计通信数据包格式,并说明各字段的定义;(总分5分)
2) 在一个实时操作系统中,你会如何部署模块中的任务和缓存数据,画出任务间的数据流视图加以说明;(总分5分)
3) 你会如何设置任务的优先级,说说优缺点;(总分5分)
4) 如果将命令码对应的处理优先级分为高、低两个等级,你又会如何设计;(总分5分)

预处理标识符

# 空指令,无任何效果
#include 包含一个源代码文件
#define 定义宏
#undef 取消已定义的宏
#if 如果给定条件为真,则编译下面代码
#ifdef 如果宏已经定义,则编译下面代码
#ifndef 如果宏没有定义,则编译下面代码
#elif 如果前面的#if给定条件不为真,当前条件为真,则编译下面代码
#endif 结束一个#if……#else条件编译块
#error 停止编译并显示错误信息

你可能感兴趣的:(嵌入式)