admin 管理员组

文章数量: 1184232


2024年3月13日发(作者:怎么把乐谱转换成代码)

2021年光电信息科学与工程专业毕业生

《C语言单片机》求职考试题及面试题试卷

(附:答案)

线

题 号 一 二 三

得 分

总 分

一、关键字Volatile。

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

一个定义为volatile的变量是说这变量可能会被意想不到地改

变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优

化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而

不是使用保存在寄存器里的备份。下面是volatile变量的几个例子:

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

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

Non-automatic variables;

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

回答不出这个问题的人是不会被雇佣的。我认为这是区分C程序

员和嵌入式系统程序员的最基本的问题。嵌入式系统程序员经常同硬

件、中断、RTOS等等打交道,所用这些都要求volatile变量。不懂

1 / 8

得volatile内容将会带来灾难。假设被面试者正确地回答了这是问

题(嗯,怀疑这否会是这样),将稍微深究一下,看一下这家伙是不

是直正懂得volatile完全的重要性。

1). 一个参数既可以是const还可以是volatile吗?解释为什

么。

2). 一个指针可以是volatile 吗?解释为什么。

3). 下面的函数有什么错误:

int square(volatile int *ptr) ;{ return *ptr * *ptr; } ;

下面是答案:

1). 是的。一个例子是只读的状态寄存器。它是volatile因为

它可能被意想不到地改变。它是const因为程序不应该试图去修改

它。

2). 是的。尽管这并不很常见。一个例子是当一个中服务子程序

修该一个指向一个buffer的指针时。

3). 这段代码的有个恶作剧。这段代码的目的是用来返指针*ptr

指向值的平方,但是,由于*ptr指向一个volatile型参数,编译器

将产生类似下面的代码:

int square(volatile int *ptr) ;{ int a,b; a = *ptr; b =

*ptr; return a * b; } ;

由于*ptr的值可能被意想不到地该变,因此a和b可能是不同

的。结果,这段代码可能返不是你所期望的平方值!正确的代码如下:

long square(volatile int *ptr) ;{ int a; a = *ptr; return

2 / 8

a * a; };

二、位操作(Bit manipulation)。

嵌入式系统总是要用户对变量或寄存器进行位操作。给定一个整

型变量a,写两段代码,第一个设置a的bit 3,第二个清除a 的bit

3。在以上两个操作中,要保持其它位不变。

对这个问题有三种基本的反应:

1). 不知道如何下手。该被面者从没做过任何嵌入式系统的工

作。

2). 用bit fields。Bit fields是被扔到C语言死角的东西,

它保证你的代码在不同编译器之间是不可移植的,同时也保证了的你

的代码是不可重用的。我最近不幸看到Infineon为其较复杂的通信

芯片写的驱动程序,它用到了bit fields因此完全对我无用,因为

我的编译器用其它的方式来实现bit fields的。从道德讲:永远不

要让一个非嵌入式的家伙粘实际硬件的边。

3). 用 #defines 和 bit masks 操作。这是一个有极高可移植

性的方法,是应该被用到的方法。最佳的解决方案如下:

#define BIT3 (0x1<<3);static int a; void set_bit3(void);

{ a |= BIT3; } ;void clear_bit3(void);{ a &= ~BIT3; };

一些人喜欢为设置和清除值而定义一个掩码同时定义一些说明

常数,这也是可以接受的。我希望看到几个要点:说明常数、|=和&=~

操作。

三、访问固定的内存位置(Accessing fixed memory locations)。

3 / 8

嵌入式系统经常具有要求程序员去访问某特定的内存位置的特

点。在某工程中,要求设置一绝对地址为0x67a9的整型变量的值为

0xaa66。编译器是一个纯粹的ANSI编译器。写代码去完成这一任务。

这一问题测试你是否知道为了访问一绝对地址把一个整型数强

制转换(typecast)为一指针是合法的。这一问题的实现方式随着个

人风格不同而不同。典型的类似代码如下:

int *ptr; ptr = (int *)0x67a9; *ptr = 0xaa55;一个较晦涩

的方法是:*(int * const)(0x67a9) = 0xaa55;

即使你的品味更接近第二种方案,但我建议你在面试时使用第一

种方案。

四、中断(Interrupts)。

1、中断是嵌入式系统中重要的组成部分,这导致了很多编译开

发商提供一种扩展—让标准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 不能传递参数。如果你没有看到这一点,你被雇用的机

4 / 8


本文标签: 代码 变量 寄存器 访问