經典回放 11道嵌入式C語言面試題剖析

2021-08-19 20:08:37 字數 2985 閱讀 7408

預處理器(preprocessor)

1 .用預處理指令#define 宣告乙個常數,用以表明1年中有多少秒(忽略閏年問題)

答: #define seconds_per_year (60 * 60 * 24 * 365)ul

我在這想看到幾件事情:

1) #define 語法的基本知識(例如:不能以分號結束,括號的使用,等等)

2) 懂得預處理器將為你計算常數表示式的值,因此,直接寫出你是如何計算一年中有多少秒而不是計算出實際的值,是更清晰而沒有代價的。

3) 意識到這個表示式將使乙個16位機的整型數溢位, 因此要用到長整型符號l, 告訴編譯器這個常數是長整型數。

4) 如果你在表示式中用到ul(表示無符號長整型),那麼可能這就給面試者留下了很好的第一印象。記住第一印象很重要。

2 .寫乙個」標準」巨集min ,這個巨集輸入兩個引數並返回較小的乙個。

答: #define min(a,b) ((a) <= (b) ? (a) : (b))

這個測試是為下面的目的而設的:

1) 標識#define在巨集中應用的基本知識。這是很重要的。因為在 嵌入(inline)操作符 變為標準c的一部分之前,巨集是方便產生嵌入**的唯一方法,對於嵌入式系統來說,為了能達到要求的效能,嵌入**經常是必須的方法。

2) 懂得在巨集中小心地把引數用括號括起來

3) 我也用這個問題開始討論巨集的***,例如:當你寫下面的**時會發生什麼事?

least = min(*p++, b);

死迴圈(infinite loops)

3.嵌入式系統中經常要用到無限迴圈,你怎麼樣用c編寫死迴圈呢?

答: 這個問題用幾個解決方案。我首選的方案是:

while(1)

下面是答案:

1)是的。乙個例子是唯讀的狀態暫存器。它是volatile因為它可能被意想不到地改變。它是const因為程式不應該試圖去修改它。

2)是的。儘管這並不很常見。乙個例子是當乙個中服務子程式修該乙個指向乙個buffer的指標時。

3)這段**有點**。這段**的目的是用來返指標*ptr指向值的平方,但是,由於*ptr指向乙個volatile型引數,編譯器將產生類似下面的**:

int square(volatile int *ptr)

由於*ptr的值可能被意想不到地該變,因此a和b的值可能不同。結果,這段**可能返回的不是你所期望的平方值。正確的**如下:

long square(volatile int *ptr)

位操作(bit manipulation)

8.嵌入式系統總是要使用者對變數或暫存器進行位操作。給定乙個整型變數a,寫兩段**,第乙個設定a的bit 3,第二個清除a 的bit 3。在以上兩個操作中,要保持其它位不變。

對這個問題有三種基本的反應:

1) 不知道如何下手。說明該面試者從沒做過任何嵌入式系統方面的工作。

2) 用bit fields。bit fields是被扔到c語言死角的東西,它保證你的**在不同編譯器之間是不可移植的,同時也保證了的你的**是不可重用的。我最近不幸看到 infineon為其較複雜的通訊晶元寫的驅動程式,他用到了bit fields,因此完全對我無用,因為我的編譯器是用其它的方式來實現bit fields的。從道德上講:永遠不要讓乙個非嵌入式的傢伙粘實際硬體的邊。

3) 用 #defines 和 bit masks 操作。這是乙個有極高可移植性的方法,是應該被用到的方法。最佳的解決方案如下:

static int a;

void set_bit3(void)

void clear_bit3(void)

訪問固定的記憶體位置(accessing fixed memory locations)

9.嵌入式系統經常具有要求程式設計師去訪問某特定的記憶體位置的特點。在某工程中,要求設定一絕對位址為0x67a9的整型變數的值為0xaa66。編譯器是乙個純粹的ansi編譯器。寫**去完成這一任務。

答:這一問題測試你是否知道為了訪問一絕對位址把乙個整型數強制轉換(typecast)為一指標是合法的。這一問題的實現方式隨著個人風格不同而不同。典型的類似**如下:

int *ptr;

ptr = (int *)0x67a9;

*ptr = 0xaa55;

乙個較晦澀的方法是:

*(int * const)(0x67a9) = 0xaa55;
即使你的品味更接近第二種方案,但我建議你在面試時使用第一種方案。

__interrupt double compute_area (double radius)

答:這個函式有太多的錯誤,以至讓人不知從何說起:

1) isr 不能返回乙個值。如果你不懂這個,那麼你不會被雇用。

2) isr 不能傳遞引數。如果你沒有看到這一點,你被雇用的機會等同第一項。

3) 在許多的處理器/編譯器中,浮點一般都是不可重入的。有些處理器/編譯器需要讓額處的暫存器入棧,有些處理器/編譯器就是不允許在isr中做浮點運算。此外,isr應該是短而有效率的,在isr中做浮點運算是不明智的。

4) 與第三點一脈相承,printf()經常有重入和效能上的問題。如果你丟掉了第三和第四點,我不會太為難你。不過,如果你能回答後兩點,那麼你的被雇用前景越來越光明。

**例子(code examples)

11 .下面的**輸出是什麼,為什麼?

void foo(void)

答:這個問題測試你是否懂得c語言中的整數自動轉換原則,我發現有些開發者對這些東西懂得極少,不管如何,這無符號整型問題的答案是輸出是 「>6」。原因是當表示式中存在有符號型別和無符號型別時所有的運算元都自動轉換為無符號型別。因此-20變成了乙個非常大的正整數,所以該表示式計算出的結果大於6。 這一點對於應當頻繁用到無符號資料型別的嵌入式系統來說是丰常重要的。如果你答錯了這個問題,也就得不到這份工作。

嵌入式C語言 swap經典

1 形參和實參中的swap include void swap1 int a,int b void swap2 int a,int b int main void void swap1 int a,int b void swap2 int a,int b swap1 c語言函式呼叫中,實參傳遞給形參...

16道嵌入式 語言面試題

預處理器 preprocessor 1.用預處理指令 define 宣告乙個常數,用以表明1年中有多少秒 忽略閏年問題 define seconds per year 60 60 24 365 ul 我在這想看到幾件事情 1 define 語法的基本知識 例如 不能以分號結束,括號的使用,等等 2 ...

嵌入式經典面試題

這些題實在太經典了 預處理器 preprocessor 1 用預處理指令 define 宣告乙個常數,用以表明1年中有多少秒 忽略閏年問題 define seconds per year 60 60 24 365 ul 我在這想看到幾件事情 1 define 語法的基本知識 例如 不能以分號結束,括...