最近面了很多公司,总结一下最近遇到的题目,很多高频出现,后来看了一下,这些都是很经典的题目,写一个笔记,日后复习,不定期更新
宏定义问题
1、写一个标准宏MIN,输入两个参数返回较小的一个
个人理解:
这个题考的事使用宏定义函数的基础,外加三目运算符的考察
我的解答:
#define MIN(a,b)((a)>=(b)?(b):(a))
2、使用宏定义 定义一个常数,一年有多少秒(忽略闰年)
个人理解:
这个题考察宏定义基本用法,还有普通平台下数据类型长度的问题在32位的设备上int是 4个byte 8位和16位是2个byte,为了兼容各平台最好使用unsigned long,以便在使用的时候不会出问题
#define SECOND_YEAR (60*60*24*360ul)
(ps. 有一种写法是
#define SECOND_YEAR (60*60*24*360)ul
,这种我没有验证,但是再16位或者8位的系统上这个数值已经大于0xffff,可能出现超出的情况,保守起见用上面的方法 )
3、宏定义#和##的区别
个人理解:
我觉得这个可能会很多人不知道后面那个,至少我是这样的,根本没有使用过##,不过在apm的源码中看到过很多次,之前没注意,现在重新温习一下
我的解答:
#define a_printf(x) printf( "token " #x" = %d\n ", token##x )
所以a_printf(1);就是相当于 printf("token 1 = %d\n",token1);
还有一个#的例子很经典
#define MONCK(ARGTERM) /
printf("The term " #ARGTERM " is a string/n")
MONCK(A to B);
输出:
The term A to B is a string
4、#error、#warning有什么用?
个人理解:
这个可能非常简单,但是很少人用,在apm源码中非常常用,因为apm要跨五六个平台,编译的时候要做出提示或者是报错
我的解答:
#define NIU_BI
#ifdef NIU_BI
#error "there is a niubi problem"
#else
#warning "ni niubi,mei mao bing"
#endif
预编译的时候会进行一个处理,如果定义了NIU_BI,那么编译器将会报错,输出后面的字符串,如果没有的话,编译器将会输出一个警告,但并不影响编译
5、如何使用可变参数的宏
个人理解:
熟悉Java的同学对这个再熟悉不过了,有点类似。确实可变参数宏在嵌入式编程中是一大利器
网络解答:
可变参数可以用三个点(...)来表示,,可以用__VA_ARGS__来展开,如:
#define err(...) fprintf(stderr,__VA_ARGS__)
err("%s %d/n","The error code: ",48);
一般,我们可以这样打印错误信息:
fprintf(stderr,"%s %d/n","The error code ",48);
但想要另外输出其它信息,我们可以这样定义一个可变参数的宏,例如:
#define errout(a,b,...) /
fprintf(stderr,"File %s Line %d/n",a,b); /
fprintf(stderr,__VA_ARGS__)
那么我们就可以这样使用这个宏:
errout(__FILE__,__LINE__,"Unexpected termination/n");
因为__VA_ARGS__在fprintf中的内部实现使用了逗号来作分割符,所以必须要求至少有一个参数,如果想使__VA_ARGS__为空,可以这样使用:
fprintf(stderr, ##__VA_ARGS__);
6、为什么要使用宏定义,有哪些注意事项?
因为 宏的效率高,不需要压栈 和出栈,而且可以节省代码
使用宏不能使用递归,宏只是进行简单替换,
定义的时候最好加上括号,确定优先级,反之在预编译的时候出现替换
造成优先级变化的问题。C语言里没有模板,而c语言的宏恰恰相当于C++的模板,
虽然宏很好用,但是还是不要过于使用宏,最好只是用于一些函数比较难实现的场景。