嵌入式軟件面試題,持續更新......

前言

作爲嵌入式軟件工程師,跳槽的時候通常會先來一份C/C++面試題。這裏總結一下自己或者網友遇到的C/C++面試題,供大家參考下。

實例

1、零值比較

//bool類型的零值比較
bool flag;

if(flag){
    if(!flag){

    }
}

//float類型的零值比較
float x;
const float EPSINON = 0.00001

if((x >= -EPSINON) && (x <= EPSINON))

//指針類型的零值比較
char *p;

if(p == NULL){
    if(p != NULL){
        
    }
}

2、sizeof

sizeof用於計算一個變量或者類型所佔的內存大小,返回單位爲字節;

char str[] = "Hello";
char *p = str;
int n = 10;

sizeof(str) = 6;//Hello佔5個字節,結尾結束符佔一個字節
sizeof(p) = 4;//一般32位機器,指針類型變量佔4個字節
sizeof(n) = 4;//一般32位機器,int類型變量佔4個字節

void Func(char str[100]){
    sizeof(str) = 4;//函數未被調用時,形參不分配內存;函數調用時,形參被分配內存,直到函數執行完            
                    //畢;傳遞的str[100]是個數組,因此傳入函數的形參可以理解爲str[100]的地址,
                    //所以佔4個字節
}

void *p = malloc(100);
sizeof(p) = 4;//同指針類型解釋

3、變量不同類型的定義

int a;//一個整型數
int *a;//一個指向整型數的指針
int **a;//一個指向指針類型的指針,其指向的指針指向一個整型數
int a[10];//一個有10個int型元素的數組
int *a[10];//一個有10個指向int型數據的指針類型元素的數組
int (*a)[10];//一個數組指針,指向有10個int型元素的數組
int (*a)(int);//一個函數指針,該函數有一個int型參數並返回一個int型數據
int (*a[10])(int);//一個有10個指針的數組,該指針指向一個函數,該函數有一個int型參數並返回一個int 
                  //型數據

4、

5、

6、

7、

8、

9、

10、

11、

12、

13、關鍵字volatile有什麼含義?並給出三個不同的例子。

A、一個定義爲volatile的變量是說這個變量可能會被意外改變,這樣,編譯器就不會去假設這個變量的值。精確地說就是,優化器在用到這個變量時必須每次都小心地重新讀取這個變量的值,而不是使用保存在寄存器裏面的備份。

B、例子

1)並行設備的硬件寄存器(如:狀態寄存器)

2)一箇中斷服務子程序中會訪問到的非自動變量

3)多線程應用中被幾個任務共享的變量

14、

 

15、頭文件中的ifndef/define/endif是爲了防止該頭文件被重複引用。

16、#include <filename.h>和#include "filename.h"有什麼區別?

#include <filename.h>是告訴編譯器,優先從標準庫開始搜索filename.h;

#include "filename.h"是告訴編譯器,優先從用戶的工作路徑開始搜索filename.h;

17、const有什麼作用?

(1)const可以修飾常量

(2)被const修飾爲只讀的變量、函數的參數、返回值會受到保護,可以防止被意外地改變,能提高程序的健壯性。

18、簡單說明一下關鍵字static和volatile的作用?

(1)static修飾一個局部變量時,生命域是全局的,作用域是局部的;

static修飾一個C源文件內的全局變量時,生命域是全局的,作用域減小隻作用於本文件;

static修飾一個函數時,生命域是全局的,作用域減小隻作用於本文件;

(2)volatile表示被修飾的變量是易變的,警告編譯器每次都要從變量的內存地址讀取,而不是讀寄存器的備份;

(3)const和volatile可以同時修飾一個變量,例如:只讀的狀態寄存器;

const和static不可以同時修飾一個變量,因爲C++編譯器在實現const的成員函數的時候爲了確保該函數不能修改類的實例的狀態,會在函數中添加一個隱式的參數const this *。但當一個成員爲static的時候,該函數是沒有this指針的。也就是說此時static的用法和static是衝突的。

19、鏈表和數組的區別?

(1)在內存中,數組是一塊連續的區域,鏈表則是隨機的離散區域。

(2)數組的查找讀取數據塊,因爲它是連續的,知道一個數據地址就能找到對應的數據;但是數組的數據插入和刪除效率低,對內存空間的要求高,必須由足夠的連續空間,有可能會造成內存浪費。

(3)鏈表的數據插入和刪除效率高,內存利用率高且拓展靈活;但是查找讀取數據慢,必須使用遍歷的方式查找數據。

20、怎麼理解中斷的過程?

中斷的過程可以順序分爲4個部分:入棧,取向量,更新寄存器和異常返回;

(1)入棧:保存現場,數據總線依次把xPSR,PC,LR,R12和R3~R0壓棧;

(2)取向量:指令總線從向量表取出服務函數入口地址;

(3)更新寄存器:更新堆棧指針SP,PSR,PC(PC指向服務函數入口地址),LR;

(4)異常返回:恢復現場(數據出棧),更新NVIC寄存器;

Tips:LR(R14)是存儲返回地址,所以當調用一級深度的子程序返回時,可以直接讀取LR中的返回地址而不用去讀內存;當多級深度時就需要把上一級的返回地址壓入堆棧;

21、中斷服務函數能有輸入參數和返回值嗎?爲什麼?

中斷服務函數不能有輸入參數和函數返回。因爲中斷從本質來說是硬件外設自動產生的一種電信號,由硬件自身調用,沒有程序去傳遞參數給硬件,硬件也不會接收參數。再者中斷處理要越快越好以確保實時操作系統內的實時性,如Linux系統的硬中斷和軟中斷機制。

22、怎麼理解信號量、互斥信號量?

(1)信號量就是一個用來表示某個資源被佔用情況的標誌。

信號量的功能:A、實現任務間的同步;B、管理多個共享資源;

(2)互斥信號量就是一個值只有0和1兩種情況的二值信號量,實現對資源的互斥訪問。

互斥信號量的功能:A、防止任務優先級反轉問題;

23、簡單說一下ARM處理器架構和C51處理器架構的區別?

(1)ARM是32位RISC(精簡指令集)微處理器架構的總稱;C51是8位CISC(複雜指令集)微處理器架構的總稱;

(2)ARM採用馮諾依曼或者哈佛的內核結構,如Cortex-M3就採用的是哈佛結構;C51採用馮諾依曼的機構內核;

24、簡單說一下,UCOS II和UCOS III的區別?

(1)UCOS II只有0~63個優先級,而且優先級不能重複;UCOS III允許幾個任務使用同一個優先級,在同一個優先級裏面,支持時間片調度。

(2)UCOS III允許用戶在程序運行中動態配置實時操作系統內核資源,避免用戶在編程中出現資源不夠用的問題。

(3)UCOS II最大支持256個任務;UCOS III支持任意的任務、信號量、消息列表和內存塊容量,只受限於用戶CPU可以使用的RAM容量;

25、簡單說一下,UCOS II中消息隊列、消息郵箱和信號量的區別?

(1)用信號量進行行爲同步時,只能提供同步的時刻信息,不能提供內容信息。若被控制方要求得到控制方的內容信息時,可以使用消息郵箱或消息隊列。

(2)但由於消息郵箱裏面只存放一條消息,所以使用消息郵箱進行任務同步時,需要滿足一個條件:消息的產生速度總要慢於消息的消費速度,即被控制任務總是在等待消息,否則會導致消息丟失。

(3)若遇到出現消息的產生速度可能快於消息的消費速度的情況時,則可以使用比消息郵箱更爲強大的消息隊列,由於消息隊列可以存放多條消息,所以消息隊列能夠有效解決消息的臨時堆積問題。但消息隊列的使用仍然需要滿足一個條件:消息的平均產生速率比消息的平均消費速率低,否則再長的消息隊列也會溢出。

26、簡單說一下,可重入函數和不可重入函數?

(1)可重入函數:重入意味着這個函數可以重複進入,可以被並行調用,可以被中斷,它只使用自身棧上的數據變量,它不依賴於任務環境,在多任務調度過程中,是安全的,不必擔心數據出錯;

(2)不可重入意味着不可被並行調度,否則會產生不可預料的結果,這些函數體內一般使用了全局變量、靜態(static)的數據結構,使用了malloc或者free函數,使用了標準I/O函數等等;

(3)可理解爲兩者互斥,凡不是不可重入函數的就是可重入函數;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章