C语言测试:想成为嵌入式程序员应知道的16个基本问题
来源:互联网 发布:在尚德公司编程怎么样 编辑:程序博客网 时间:2024/05/17 06:33
预处理器(Preprocessor)
我在这想看到几件事情:
; 懂得预处理器将为你计算常数表达式的值,因此,直接写出你是如何计算一年中有多少秒而不是计算出实际的值,是更清晰而没有代价的。
; 意识到这个表达式将使一个16位机的整型数溢出-因此要用到长整型符号L,告诉编译器这个常数是的长整型数。
; 如果你在你的表达式中用到UL(表示无符号长整型),那么你有了一个好的起点。记住,第一印象很重要。
#define MIN(A,B) ((A) <= (B) ? (A) : (B))
; 三重条件操作符的知识。这个操作符存在C语言中的原因是它使得编译器能产生比if-then-else更优化的代码,了解这个用法是很重要的。
; 懂得在宏中小心地把参数用括号括起来
; 我也用这个问题开始讨论宏的副作用,例如:当你写下面的代码时会发生什么事?
least = MIN(*p++, b);
死循环(Infinite loops)
{
?}
{
?}
...
goto Loop;
b)一个指向整型数的指针( A pointer to an integer)
c)一个指向指针的的指针,它指向的指针是指向一个整型数( A pointer to a pointer to an intege)r
d)一个有10个整型数的数组( An array of 10 integers)
e) 一个有10个指针的数组,该指针是指向一个整型数的。(An array of 10 pointers to integers)
f) 一个指向有10个整型数数组的指针( A pointer to an array of 10 integers)
g) 一个指向函数的指针,该函数有一个整型参数并返回一个整型数(A pointer to a function that takes an integer as an argument and returns an integer)
h) 一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数( An array of ten pointers to functions that take an integer argument and return an integer )
a) int a; // An integer
b) int *a; // A pointer to an integer
c) int **a; // A pointer to a pointer to an integer
d) int a[10]; // An array of 10 integers
e) int *a[10]; // An array of 10 pointers to integers
f) int (*a)[10]; // A pointer to an array of 10 integers
g) int (*a)(int); // A pointer to a function a that takes an integer argument and returns an integer
h) int (*a[10])(int); // An array of 10 pointers to functions that take an integer argument and return an integer
人们经常声称这里有几个问题是那种要翻一下书才能回答的问题,我同意这种说法。当我写这篇文章时,为了确定语法的正确性,我的确查了一下书。但是当我被面试的时候,我期望被问到这个问题(或者相近的问题)。因为在被面试的这段时间里,我确定我知道这个问题的答案。应试者如果不知道所有的答案(或至少大部分答案),那么也就没有为这次面试做准备,如果该面试者没有为这次面试做准备,那么他又能为什么出准备呢?
; 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。
; 在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用。
大多数应试者能正确回答第一部分,一部分能正确回答第二部分,同是很少的人能懂得第三部分。这是一个应试者的严重的缺点,因为他显然不懂得本地化数据和代码范围的好处和重要性。
Const
下面的声明都是什么意思?
int const a;
const int *a;
int * const a;
int const * a const;
前两个的作用是一样,a是一个常整型数。第三个意味着a是一个指向常整型数的指针(也就是,整型数是不可修改的,但指针可以)。第四个意思a是一个指向整型数的常指针(也就是说,指针指向的整型数是可以修改的,但指针是不可修改的)。最后一个意味着a是一个指向常整型数的常指针(也就是说,指针指向的整型数是不可修改的,同时指针也是不可修改的)。如果应试者能正确回答这些问题,那么他就给我留下了一个好印象。顺带提一句,也许你可能会问,即使不用关键字 const,也还是能很容易写出功能正确的程序,那么我为什么还要如此看重关键字const呢?我也如下的几下理由:
; 通过给优化器一些附加的信息,使用关键字const也许能产生更紧凑的代码。
; 合理地使用关键字const可以使编译器很自然地保护那些不希望被改变的参数,防止其被无意的代码修改。简而言之,这样可以减少bug的出现。
Volatile
8. 关键字volatile有什么含意?并给出三个不同的例子。
; 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
; 多线程应用中被几个任务共享的变量
回答不出这个问题的人是不会被雇佣的。我认为这是区分C程序员和嵌入式系统程序员的最基本的问题。搞嵌入式的家伙们经常同硬件、中断、RTOS等等打交道,所有这些都要求用到volatile变量。不懂得volatile的内容将会带来灾难。
; 一个指针可以是volatile 吗?解释为什么。
; 下面的函数有什么错误: int square(volatile int *ptr)
{
return *ptr * *ptr;
}
; 是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指向一个buffer的指针时。
; 这段代码有点变态。这段代码的目的是用来返指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码: int square(volatile int *ptr)
{
int a,b;
a = *ptr;
b = *ptr;
return a * b;
}
{
int a;
a = *ptr;
return a * a;
}
; 用bit fields。Bit fields是被扔到C语言死角的东西,它保证你的代码在不同编译器之间是不可移植的,同时也保证了的你的代码是不可重用的。我最近不幸看到 Infineon为其较复杂的通信芯片写的驱动程序,它用到了bit fields因此完全对我无用,因为我的编译器用其它的方式来实现bit fields的。从道德讲:永远不要让一个非嵌入式的家伙粘实际硬件的边。
; 用 #defines 和 bit masks 操作。这是一个有极高可移植性的方法,是应该被用到的方法。最佳的解决方案如下: #define BIT3 (0x1 << 3)
static int a;
a |= BIT3;
}
void clear_bit3(void) {
a &= ~BIT3;
}
访问固定的内存位置(Accessing fixed memory locations)
10. 嵌入式系统经常具有要求程序员去访问某特定的内存位置的特点。在某工程中,要求设置一绝对地址为0x67a9的整型变量的值为0xaa66。编译器是一个纯粹的ANSI编译器。写代码去完成这一任务。
ptr = (int *)0x67a9;
*ptr = 0xaa55;
一个较晦涩的方法是:
{
double area = PI * radius * radius;
printf("/nArea = %f", area);
return area;
}
; ISR 不能传递参数。如果你没有看到这一点,你被雇用的机会等同第一项。
; 在许多的处理器/编译器中,浮点一般都是不可重入的。有些处理器/编译器需要让额处的寄存器入栈,有些处理器/编译器就是不允许在ISR中做浮点运算。此外,ISR应该是短而有效率的,在ISR中做浮点运算是不明智的。
; 与第三点一脉相承,printf()经常有重入和性能上的问题。如果你丢掉了第三和第四点,我不会太为难你的。不用说,如果你能得到后两点,那么你的被雇用前景越来越光明了。
*****
代码例子(Code examples)
{
unsigned int a = 6;
int b = -20;
(a+b > 6) ? puts("> 6") : puts("<= 6");
}
unsigned int compzero = 0xFFFF;
/*1's complement of zero */
if ((ptr = (char *)malloc(0)) ==
NULL)
else
puts("Got a null pointer");
puts("Got a valid pointer");
Typedef
:
15 Typedef 在C语言中频繁用以声明一个已经存在的数据类型的同义字。也可以用预处理器做类似的事。例如,思考一下下面的例子:
typedef struct s * tPS;
这是一个非常微妙的问题,任何人答对这个问题(正当的原因)是应当被恭喜的。答案是:typedef更好。思考下面的例子:
tPS p3,p4;
c = a+++b;
1 定义全局变量的时候是否要附初值?
- C语言测试:想成为嵌入式程序员应知道的16个基本问题
- C语言测试:想成为嵌入式程序员应知道的16个基本问题
- C语言测试:想成为嵌入式程序员应知道的0x10个基本问题
- C语言测试:想成为嵌入式程序员应知道的0x10个基本问题
- C语言测试:想成为嵌入式程序员应知道的0x10个基本问题
- C语言测试:想成为嵌入式程序员应知道的0x10个基本问题
- C语言测试:想成为嵌入式程序员应知道的0x10个基本问题
- C语言测试:想成为嵌入式程序员应知道的0x10个基本问题-
- C语言测试:想成为嵌入式程序员应知道的0x10个基本问题
- C语言测试:想成为嵌入式程序员应知道的0x10个基本问题
- C语言测试:想成为嵌入式程序员应知道的0x10个基本问题
- C语言测试:想成为嵌入式程序员应知道的0x10个基本问题
- C语言测试:想成为嵌入式程序员应知道的0x10个基本问题
- C语言测试:想成为嵌入式程序员应知道的0x10个基本问题
- C语言测试:想成为嵌入式程序员应知道的0x10个基本问题
- C语言测试:想成为嵌入式程序员应知道的0x10个基本问题
- C语言测试:想成为嵌入式程序员应知道的0x10个基本问题 zz
- C语言测试:想成为嵌入式程序员应知道的0x10个基本问题
- 无名管道系统调用
- div background 不显示
- 犯了一个可笑的错误(数据库未Post)
- Android系统自带theme
- 校园网802.1登录内网外网方法和常见问题汇总[ubuntu]
- C语言测试:想成为嵌入式程序员应知道的16个基本问题
- Oracle Pipelined Table Functions简介
- js中常用的东东
- Could not get lock /var/lib/apt/lists/lock
- oracle JOB使用方法
- 设计模式-结构型模式-访问者
- 输入一个单向链表,输出该链表中倒数第k个结点,链表的倒数第0个结点为链表的尾指针
- Oracle数据库权限管理学习笔记
- 一个挺无聊的问题