嵌入式面试c语言部分总结

来源:互联网 发布:黄心和绿心猕猴桃 知乎 编辑:程序博客网 时间:2024/05/21 17:35
  1. 用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题)
#define YEAR_PRE_SCEOND  (365*24*60*60)

2.已知一个数组table,用一个宏定义,求出数据的元素个数

#define TAB_SIZE ( sizeof(table) / sizeof(table{0}) )

3.写一个”标准”宏MIN ,这个宏输入两个参数并返回较小的一个

#define MIN(A, B)  ( (A) > (B) ? (B) : (A) )

但是当出现

least = MIN(*p++, b);  宏MIN 会把*p++执行两次,即( (*p++) > (b) ? (*p++) : (b) )

4.嵌入式系统总是要用户对变量或寄存器进行位操作。给定一个整型变量a,写两段代码,第一个设置a的bit 3,第二个清除a 的bit 3。在以上两个操作中,要保持其它位不变。

#define BIT3 (0x01 << 3)Int a;a |= BIT3;  //seta &=~ BIT3;  //clc

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

int *a;a = (Int *) 0x67a9;*a = 0xaa66;
((void (*)( )) 0x67a9) ();

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

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

输出 > 6 ,unsigned int 6 是 0x0006 , 而 int -20 是 0x8014 在相加时 是按照无符号相加的所以其值大于 6
8. (void )ptr 和 ((void**))ptr的结果是否相同?其中ptr为同一个指针
结果相同,但是ptr不是同一指针 ,第一个是 void * 型,第二个是void ** 型
9.int a=2,b=11,c=a+b++/a++; 则c值为多少?

c = a +(b++ / a++);

10.关键字static
Static 静态变量
如果在函数内声明,表明在调用函数时保留上一次其值。
如果在模块内声明,表明是一个本地全局变量,对模块外不可见,模块外函数都不能访问。
如果声明一个函数,表明该函数只能被模块内函数调用,对外不可见,可以避免在多人协作开发项目是函数重名问题。
11.关键字 Const
Const 只读,主要目的是防止在后面编程中无意间修改,减少bug出现。

const int a;            //a为常量int const a;            //a为常量const int *a;           //a 为常量 指针a可修改int * const a;          //*a 可修改 指针a 不可修改int const * const a ;   // *a 和 a 都不能被修改

12.关键字volatile
volatile的变量 编译器不做优化,在运行程序时不做缓存,每次调用时都必须重新读变量值。多用于共享设备中。
如:
并行设备寄存器(如:状态寄存器)
一个中断服务子程序中会访问到的非自动变量
多线程应用中被几个任务共享的变量
1) 一个参数既可以是const还可以是volatile吗?解释为什么。
可以,例如:只读状态寄存器,const表明不容许程序被修改,volatile 表明不做缓存其值会随时改变。
2) 一个指针可以是volatile 吗?解释为什么。
可以。
volatile修饰指针一般用在共享指针上面。
下面代码:

uchar * volatile reg;

行代码里volatile修饰的是reg这个变量。所以这里实际上是定义了一个uchar类型的指针,并且这个指针变量本身是volatile 的。但是指针所指的内容并不是volatile的!在实际使用的时候,编译器对代码中指针变量reg本身的操作不会进行优化,但是对reg所指的内容 reg却会作为non-volatile内容处理,对reg的操作还是会被优化。通常这种写法一般用在对共享指针的声明上,即这个指针变量有可能会被中断等函数修改。将其定义为volatile以后,编译器每次取指针变量的值的时候都会从内存中载入,这样即使这个变量已经被别的程序修改了当前函数用的时候也能得到修改后的值(否则通常只在函数开始取一次放在寄存器里,以后就一直使用寄存器内的副本)。
3) 下面的函数有什么错误:

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

其本意是求平方,但是volatile变量会随时修改,有可能在计算时其中一个被修改。还有两个int相乘又可能溢出,应该用 long
正确方法

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

13.Typedef 在C语言中频繁用以声明一个已经存在的数据类型的同义字。也可以用预处理器做类似的事。例如,思考一下下面的例子:

#define dPS struct s *typedef struct s * tPS;

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

dPS p1,p2;tPS p3,p4;
第一个扩展为struct s * p1, p2;第二个扩展为Struct s * p1, Struct s * p2

.
上面的代码定义p1为一个指向结构的指,p2为一个实际的结构,这也许不是你想要的。第二个例子正确地定义了p3 和p4 两个指针。
14.中断是嵌入式系统中重要的组成部分,这导致了很多编译开发商提供一种扩展—让标准C支持中断。具代表事实是,产生了一个新的关键字 __interrupt。下面的代码就使用了__interrupt关键字去定义了一个中断服务子程序(ISR),请评论一下这段代码的。

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

中断不能有返回值。
中断不能传递参数。
浮点运算耗费时间,中断一般短而高效的。
重入性问题,在许多的处理器/编译器中,浮点一般都是不可重入的。有些处理器/编译器需要让额处的寄存器入栈,有些处理器/编译器就是不允许在ISR中做浮点运算。Printf()也有重入性问题。
重入性解释:
可重入的函数必须满足以下三个条件:
(1)可以在执行的过程中可以被打断;
(2)被打断之后,在该函数一次调用执行完之前,可以再次被调用(或进入,reentered)。
(3)再次调用执行完之后,被打断的上次调用可以继续恢复执行,并正确执行。
常见的不可重入函数有:
printf ——–引用全局变量stdout
malloc ——–全局内存分配表
free ——–全局内存分配表

0 0
原创粉丝点击