最近不少小伙伴在找工作,这里我给大家分享一下面试中经常会遇到的一些嵌入式C语言问题,你看看能答上来几个呢?
1
用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题)
#define SEC_YEAR (365*24*60*60)UL
考察点:
#define 语法的基本知识(例如:不能以分号结束,括号的使用,等等)
懂得预处理器将为你计算常数表达式的值,因此,直接写出你是如何计算一年中有多少秒而不是计算出实际的值,是更清晰而没有代价的。
意识到这个表达式将使一个16位机的整型数溢出-因此要用到长整型符号L,告诉编译器这个常数是的长整型数
如果你在你的表达式中用到UL(表示无符号长整型),那么你有了一个好的起点。记住,第一印象很重要。
2
写一个"标准"宏MIN ,这个宏输入两个参数并返回较小的一个。
#define MIN(a,b) ((a)<=(b)?(a):(b))
考察点:
标识#define在宏中应用的基本知识。这是很重要的。因为在 嵌入(inline)操作符 变为标准C的一部分之前,宏是方便产生嵌入代码的唯一方法,对于嵌入式系统来说,为了能达到要求的性能,嵌入代码经常是必须的方法。
懂得在宏中小心地把参数用括号括起来
我也用这个问题开始讨论宏的副作用,例如:当你写下面的代码时会发生什么事?
least = MIN(*p++, b);
宏定义的作用结果MIN(*p++,b) ((*p++)<(b)?(*p++),b) 指针p会做两次自增操作
如何消除宏的副作用
#include <stdio.h>
#define min_i(x,y) ((x)<=(y)?(x):(y)) //(1)
#define min_t(type,x,y) ({type _x = x;\ //(2)
type _y = y;\
_x<_y?_x:_y;\
})
#define min(x,y) {const typeof(x) _x = (x);\ //(3)
const typeof(y) _y = (y);\
(void)(&_x=&_y);\ //(4)
_x<_y?_x:_y;\
})
int main()
{
int a = 10;
int b = 20;
printf("min_i(a++,b++)=%d\n",min_i(a++,b++)); //11
printf("a=%d\n",a); //12
printf("b=%d\n",b); //21
a=10;
b=20;
printf("min_t(int,a++,b++)=%d\n",min_t(int,a++,b++)); //10
printf("a=%d\n",a); //11
printf("b=%d\n",b); //21
a=10;
b=20;
printf("min(a++,b++)=%d\n",min(a++,b++)); //10
printf("a=%d\n",a); //11
printf("b=%d\n",b); //21
}
这个定义计算x和y分别两次(x和y中的小者被计算两次),当参数由副作用时,将产生不正确的结果
使用语句表达式只计算参数一次,避免了可能的错误,语句表达式通常用于宏定义
typeof(x)表示x的值类型
检查参数x和y的类型是否相同(如果x和y的类型不同编译器将会发出warning,并不影响后面语句的运行
3
预处理器标识#error的目的是什么?
编译程序时,只要遇到 #error 就会跳出一个编译错误,既然是编译错误,要它干嘛呢?其目的就是保证程序是按照你所设想的那样进行编译的。
下面举个例子:程序中往往有很多的预处理指令
#ifdef XXX
...
#else
...
#endif
当程序比较大时,往往有些宏定义是在外部指定的(如makefile),或是在系统头文件中指定的,当你不太确定当前是否定义了 XXX 时,就可以改成如下这样进行编译:
#ifdef XXX
...
#error "XXX has been defined"
#else
#endif
这样,如果编译时出现错误,输出了XXX has been defined,表明宏XXX已经被定义了。 |