嵌入式C笔试的一点体会

1. 关键字static的作用是什么?

1),在一个函数体内一个被声明成static的变量,会保持其上次调用的值,其在函数体内赋的初值语句已无效

2),在一个模块内被声明成staitc的变量(但不在函数体内),它可以被当前模块内的所有函数访问,但不能被模块外的函数访问,它是一个本地局部变量

3),在一个模块内被声明成static的函数只能被当前模块内的函数调用,模块外的函数无法调用

个人经验,第一个作用,我在写触摸屏驱动的时候,WinCE驱动的中断处理中要会两种情况,需要查看两个各自的状态,这时候需要一个flag,我就是声明成static的,两种情况处理后会重新标记flag.

第二个第三个作用保证代码的安全性,特别在驱动编写过程中.很多内核代码也是用static

 

2.关键字const是什么含意?

我只要一听到被面试者说:“const意味着常数”,我就知道我正在和一个业余者打交道。

去年Dan Saks已经在他的文章里完全概括了const的所有用法,因此ESP(译者:Embedded Systems Programming)的每一位读者应该非常熟悉const能做什么和不能做什么.如果你从没有读到那篇文章,只要能说出const意味着“只读”就可以了。尽管这个答案不是完全的答案,但我接受它作为一个正确的答案。(如果你想知道更详细的答案,仔细读一下Saks的文章吧。)如果应试者能正确回答这个问题,我将问他一个附加的问题:下面的声明都是什么意思? 

const int a;
int const a;
const int *a;
int * const a;
int const * a const;


如果别人一直强调什么东西很重要,而你又几乎不知道为什么他们这样说,注意了,到你遇到类似的代码,要仔细的想想, 里面的精妙你要认真体会.

要理解const的修饰字的位置就好办了,const总是修饰它前面的东西,如果在最前面,就把位置和它后面的调换一下;所以const int a;和int const a;是同样的意思定义一个整型的常量a;

如果有*,如果它在*左侧,修饰的是所定义的指针变量,即变量是常,如果在*号右侧,刚其修饰的是指针,刚指针指向是常

这里要区别一下const int * a;等价于int const *a;根据上面的原是分析,它的意思是指向常量a的指针变量,指针可以变化,指向的内容是常量

那么int *const a;它是定义一个指向整型变量a的常指针,该指针不可以修改,而指向的变量可以修改.

最后一个*号左边和右边都有const,那么它就是一个指向常整型的常指针

以下是参考答案:

前两个的作用是一样,a是一个常整型数。

第三个意味着a是一个指向常整型数的指针(也就是,整型数是不可修改的,但指针可以)

第四个意思a是一个指向整型数的常指针(也就是说,指针指向的整型数是可以修改的,但指针是不可修改的)

最后一个意味着a是一个指向常整型数的常指针(也就是说,指针指向的整型数是不可修改的,同时指针也是不可修改的)。

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

使用volatile修饰说明这个变量随时发生意想不到的改变,要小心读取,这样编译器就会假设这个变量的值,防止被编译器优化掉,在编译的时候,优化器在读到这个变量时会小心的重新读取这个变量的值,而不是使用保存在寄存器的备份.

以下是三种不同的例子:

1). 并行设置的硬件寄存器(一些中断状态寄存器)

2). 一个中断子程序的会访问到的非自动变量(一些Flag标记,在其他地方可以已经修改)

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

以下几问题可以帮助理解

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 a * a;

}

4. 给定一个整型变量a,写两段代码,第一个设置a的bit 3,第二个清除a 的bit 3。在以上两个操作中,要保持其它位不变

#define BIT3  (0x1<<3)
void set_bit3(void)
{
   a |= BIT3;
}
void clear_bit3(void)
{
   a &= ~BIT3;
}


4. 嵌入式系统经常具有要求程序员去访问某特定的内存位置的特点。在某工程中,要求设置一绝对地址为0x67a9的整型变量的值为0xaa66,编译器是一个纯粹的ANSI编译器,写代码去完成这一任务

这一问题测试你是否知道为了访问一绝对地址把一个整型数强制转换(typecast)为一指针

是合法的。这一问题的实现方式随着个人风格不同而不同。典型的类似代码如下

int *ptr;
ptr = (* int )0x76a9;
*ptr = 0xaa66;

在实际的编程中,一般是将硬件地址定义成宏

#define GPBCON              (*(volatile unsigned long *)0x56000010)

#define GPB5_OUT         (1<<(5*2))

GPBCON = GPB5_OUT;

如果要读取这个数据,则可以如下:

unsinged long val;

val = GPBCON;

5. 中断的处理函数说明

__interrupt double compute_area (doubleradius)
{
  double area = PI * radius * radius;
  printf(" Area = %f", area);
  return area;
}

说出以上代码有没有什么问题

1).浮点运算不应该出现

2).不应该出现printf这样的阻塞的函数,太影响中断的处理过程了,这个函数执行太慢.

3).中断函数不应有参数传递

4).中断函数不应有返回值

 

6 . 下面的代码输出是什么,为什么?

void foo(void)
{
      unsigned int a =6;
      int b = -20;
      (a+b > 6)puts("> 6") : puts("<= 6");
}


很明显是>6.为什么呢.这里根据C中类型自动转换, int型会转换成unsigned int型进行计算,那么-20会变成很大的一个正整数.所以结果就很显而易见了.

这里不得不说一下,谭老的书还是要经常看看,3.7各类型数据混合运算有讲.

 

7. 思考一下下面的例子:

#define dPS struct s *

typedef struct s * tPS;

 

以上两种情况的意图都是要定义dPS 和 tPS 作为一个指向结构s指针。哪种方法更好呢?(如果有的话)为什么?

用typedef会更好,define会有一些意想不到的副作用,简单的替换时可能会因为某些符号的接合性导致有些很难查到到问题

如下面两两种写法

1). dPS p1,p2;

2). tPS p1,p2;

1的扩展结果是 struct s*p1,p2; p1是指针结构,p2不是指针结构了

2扩展结果是两个指向结构体的指针p1,p2

8. C语言同意一些令人震惊的结构,下面的结构是合法的吗,如果是它做些什么?

int a = 5, b = 7, c;

c = a+++b;

这个问题是测试应征者是否记得优先级结合性的问题,++的优先级是高于+的,同时由于++是右结合性的,这个语句就可以这样的看c = a++ +b;当然写出这样的代码是被BS的,不易读呀,大哥,除非你的这个程序不想让别人知道其意图,如果真的是要这么做,请用括号表明意图,c = (a++) + b;

上面语句的运行结果是:运行后,a=6,b=7,c=12

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值