嵌入式經典面試題及解析
基礎部分考察
1、用預處理指令#define 聲明一個常數,用以表明1年中有多少秒(忽略閏年問題)
#define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL
考點
01
#define 語法的基本知識(例如:不能以分號結束,括號的使用,等等)
02
懂得預處理器將為你計算常數表達式的值,因此直接寫出你如何計算一年中有多少秒而不是計算出實際的值,是更清晰而沒有代價的。
03
意識到這個表達式將使一個16位機的整型數溢出-因此要用到長整型符號L,告訴編譯器這個常數是的長整型數。
04
如果你在你的表達式中用到UL(表示無符號長整型),那么你有了一個好的起點。記住,第一印象很重要。
2、寫一個"標准"宏MIN,這個宏輸入兩個參數並返回較小的一個。
#define MIN(A,B) ((A) <= (B) ? (A) : (B))
考點
01
#define 標示在宏中應用的基本知識。這是很重要的。因為在 嵌入(inline)操作符變為標准C的一部分之前,宏是方便產生嵌入代碼的唯一方法,對於嵌入式系統來說,為了能達到要求的性能,嵌入代碼經常是必須的方法。
02
三重條件操作符的知識。這個操作符存在C語言中的原因是它使得編譯器能產生比IF-then-else更優的代碼,了解這個用法是很重要的。
03
懂得在宏中小心地把參數用括號括起來
04
我也用這個問題開始討論宏的副作用,例如:當你寫下面的代碼時會發生什么事? least = MIN(*p++, b);
3、預處理器標識#error的目的是什么?
編譯程序時,只要遇到 #error 就會跳出一個編譯錯誤,既然是編譯錯誤,要它干嘛呢?其目的就是保證程序是按照你所設想的那樣進行編譯的。
下面舉個例子:
程序中往往有很多的預處理指令
#ifdef XXX
...
#else
#endif
當程序比較大時,往往有些宏定義是在外部指定的(如makefile),或是在系統頭文件中指定的,當你不太確定當前是否定義了 XXX 時,就可以改成如下這樣進行編譯:
#ifdef XXX
...
#error "XXX has been defined"
#else
#endif
這樣,如果編譯時出現錯誤,輸出了XXX has been defined,表明宏XXX已經被定義了。
4、嵌入式系統中經常要用到無限循環,你怎么樣用C編寫死循環呢?
這個問題有幾個解決方案,我首選的方案是:
while(1)
{
}
一些程序員更喜歡如下方案:
for(;;)
{
}
因為這個題目沒有確切表達到底怎么回事,面試官將用這個作為一個機會去探究他們這樣做的基本原理。
第三個方案是用 goto
Loop:
...
goto Loop;
應試者如給出上面的方案,這說明或者他是一個匯編語言程序員(這也許是好事)或者他是一個想進入新領域的BASIC/FORTRAN程序員。
5、用變量a給出下面的定義
a) 一個整型數(An integer)
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
6 、下面的代碼輸出是什么,為什么?
void foo(void)
{
unsigned int a = 6;
int b= -20;
(a+b> 6) ? puts("> 6") : puts("<= 6");
}
考點
這個問題測試你是否懂得C語言中的整數自動轉換原則,有些開發者懂得極少這些東西。
不管如何,這無符號整型問題的答案是輸出是 ">6"。原因是當表達式中存在有符號類型和無符號類型時所有的操作數都自動轉換為無符號類型。
因此-20變成了一個非常大的正整數,所以該表達式計算出的結果大於6。這一點對於應當頻繁用到無符號數據類型的嵌入式系統來說是非常重要的。如果你答錯了這個問題,你也就到了得不到這份工作的邊緣。
7、評價下面的代碼片段
unsigned int zero =0;
unsigned intcompzero = 0xFFFF;
/*1''s complementof zero */
對於一個int型不是16位的處理器來說,上面的代碼是不正確的。應編寫如下:
unsigned intcompzero = ~0;
這一問題真正能揭露出應試者是否懂得處理器字節的重要性。在我的經驗里,好的嵌入式程序員非常准確地明白硬件的細節和它的局限,然而PC機程序往往把硬件作為一個無法避免的煩惱。