找工作筆試面試題目集(嵌入式軟件篇)----持續更新

這裏將自己遇到的,做錯的題目進行一個記錄和整理。

1.C語言函數中,strcpy和memcpy的區別是什麼?

答:strcpy和memcpy都是將存儲器的東西複製到另一個存儲器。但是這兩個的區別在於:

  • strcpy常用於複製字符串,而memcpy可以複製任何內容。
  • strcpy在複製字符串的時候,不需要指定長度,它會一直複製直到字符串的結束符“\0”,連同結束符共同複製後結束複製,因此如果複製的對象不是個字符串,那麼就會一直複製下去,因此不能用於複製其他內容。memcpy在複製的時候,除了需要指定起始地址之外,還需要指定複製的長度。

2.static的作用?

答:static關鍵字用於在變量定義時修飾變量。其作用主要有以下幾點:

  • 設置變量的存儲域,函數體內static變量的作用範圍爲該函數體,不同於auto變量,該變量的內存只被分配一次,因此其值在下次調用時仍維持上次的值;
  • 限制變量的作用域,在模塊內的static全局變量可以被模塊內所用函數訪問,但不能被模塊外其它函數訪問;
  • 限制函數的作用域,在模塊內的static函數只可被這一模塊內的其它函數調用,這個函數的使用範圍被限制在聲明它的模塊內;

具體來說,其表現爲:

  • 當static修飾局部變量時(該局部變量被稱爲靜態局部變量),其存儲位置發生改變。通常情況下,局部變量存儲在棧區,但是靜態局部變量存儲在靜態區(關於存儲分區的作用,將在後面進行詳解)。實際上局部變量修飾的全局變量,也存儲在靜態區。由於靜態局部變量的存儲位置唯一確定,因此帶來的效果是,該變量只會被初始化一次,其值在下次調用時仍維持上次的值,且該變量的生命週期被延長,直到程序結束才銷燬。
  • 當static修飾全局變量時,原來可以通過extern來使用沒有包含聲明的全局變量,但是對於靜態全局變量,只有包含了該靜態變量的聲明,才能夠使用該全局變量。
  • 當static修飾函數時,只有包含了該靜態函數的聲明,才能夠使用該函數。

3.如何在外部訪問static變量?

答:對於static變量,雖然其作用於範圍確定了,一般來說外部是不能訪問的,但是其存儲空間是唯一確定的,因此如果能夠得到該變量在存儲器中的地址,那麼我們就可以通過取地址的方式得到該變量的數值。

4.存儲器中都有哪些存儲區,其意義是什麼?

答:代碼區、常量區、靜態區(全局區)、堆區、棧區。各種區的意義是:

  • 代碼區(Code):
    顧名思義,代碼區所存放的數據是程序代碼,爲只讀性的存儲,且掉電不丟失。以STM32爲例,其代碼區所存放的物理介質爲Flash,其起始地址一般爲0x0800 0000。

  • 常量區(RO-data):
    常量區存儲的數據爲所定義的常量和常量字符串,也爲只讀性存儲,且掉電不丟失。以STM32爲例,其常量區所存放的物理介質爲Flash,其起始地址一般在代碼區之後。

  • 靜態區(RA-data & ZI-data):
    靜態區存儲的數據爲靜態變量和全局變量,這些變量在程序開始的時候存在,其生命週期直到本次程序結束,爲可讀寫性的存儲,掉電丟失。以STM32爲例,其靜態區所存放的物理介質爲RAM,其起始地址一般爲0x2000 0000。此外,靜態區中已經初始化的靜態變量和全局變量,存放在靜態區中的一部分,稱爲RA-data,沒有被初始化的靜態變量和全局變量,系統默認初始化爲0存放在靜態區中的另一部分,稱爲ZI-data。

  • 堆區(heap):
    堆區是內存中定義的一塊存儲區域,其目的是爲程序員提供一個可以自行分配使用的內存空間,堆區中的內存池由程序員通過malloc函數申請,使用完成後要由程序員通過free函數進行釋放,沒有釋放的內存將一直被佔用直到程序結束。在STM32中可以在如 Heap_Size EQU 0x00000200中,通過設置後面的地址空間大小來設置堆區的大小,此外堆區也是RAM中的一部分,因此也會掉電丟失。

  • 棧區(stack)
    棧區同樣是內存中定義的一塊存儲區域,其目的是爲程序提供一個靈活的內存空間以存放臨時數據,因此棧區是由編譯器自動分配和釋放 ,用於存放函數的參數值、局部變量的值、中斷現場等臨時數據,當操作完成後,棧中的數據就會被釋放。在STM32中可以在如 Stack_Size EQU 0x00000400中,通過設置後面的地址空間大小來設置棧區的大小,此外棧區也是RAM中的一部分,因此也會掉電丟失。棧區與堆區的區別在於,堆區是程序員自行分配和釋放,較爲靈活,但是對處理器的佔用較大以及安全性較差;而棧區是由處理器本身自行分配和釋放,程序員無法控制,因此靈活性差,但是速度快,且安全,不易出現內存沒有被回收的情況。
    (堆和棧的區別可以用如下的比喻來看出:使用棧就象我們去飯館裏喫飯,只管點菜(發出申請)、付錢、和喫(使用),喫飽了就走,不必理會切菜、洗菜等準備工作和洗碗、刷鍋等掃尾工作,他的好處是快捷,但是自由度小。使用堆就象是自己動手做喜歡喫的菜餚,比較麻煩,但是比較符合自己的口味,而且自由度大)

5.進程間的通訊方式是什麼?

答:由於進程在運行的時候,相互之間可能存在着一定的關係,例如不同的進程都要使用相同的外設,那麼這兩個進程之間的運行就是互斥的;或者有些進程的運行存在着先後次序等關係。如何保證進程之間的正常工作,就需要進程之間通過通訊的方式傳遞信息。
通信的基本原理就是,通過一個多個進程都可以訪問的載體,來在進程之間傳遞數據。根據該載體的結構不同,具體方法有:

  • 匿名管道(pipe)以及命名管道(named pipe):
    在linux系統中,對於有親屬關係的進程之間可以通過匿名管道通訊。對於無親屬關係進程之間,可以通過命名管道通信。
  • 信號量與信號量集:
    信號量是一種標誌式的數據結構,其所傳遞的信息往往是某種狀態,例如某些共享設備的被佔用情況等。信號量集就是實現了多個信號量組合的數據結構。
  • 消息與消息隊列:
    消息是一種指針式的數據結構,其所傳遞的信息往往是某些數據,例如像其他進程傳遞一些參數或字符串等。消息隊列就是由多個消息組成的鏈表結構,可以傳遞更多的數據。
  • 共享內存:
    多個進程也可以共同訪問一塊內存空間,這種通信方式比較塊,但是由於這種通信方式不具備同步和互斥機制,往往需要使用信號量或鎖來配合使用。
  • 套接字(socket):
    對於網絡上不同進程之間的通信,常採用套接字的方法來實現。套接字所表示的端口號,就是用於數據通訊的介質,進程之間通過將數據傳輸到socket所表示的端口中,由發送設備將數據發送到接收設備的socket端口中,接收設備的進程再從接收設備的socket端口中得到數據,即完成一次通信。

6.什麼是死鎖?

答:死鎖是指兩個或兩個以上的進程在執行過程中,由於競爭資源或者由於彼此通信而造成的一種阻塞的現象,若無外力作用,它們都將無法推進下去。舉例來說,線程1使用了資源A,請求使用資源B,而線程2使用了資源B,請求使用資源A,這樣這兩個進程就由於始終無法得到所需要的資源從而永遠的阻塞運行。產生死鎖的四個條件是:

  1. 互斥條件:進程要求對所分配的資源進行排它性控制,即在一段時間內某資源僅爲一進程所佔用。
  2. 請求和保持條件:當進程因請求資源而阻塞時,對已獲得的資源保持不放。
  3. 不剝奪條件:進程已獲得的資源在未使用完之前,不能剝奪,只能在使用完時由自己釋放。
  4. 環路等待條件:在發生死鎖時,必然存在一個進程–資源的環形鏈。

因此解決死鎖的方法是:

  1. 資源一次性分配:一次性分配所有資源,這樣就不會再有請求了:(破壞請求條件)
  2. 只要有一個資源得不到分配,也不給這個進程分配其他的資源:(破壞保持條件)
  3. 可剝奪資源:即當某進程獲得了部分資源,但得不到其它資源,則釋放已佔有的資源(破壞不可剝奪條件)
  4. 資源有序分配法:系統給每類資源賦予一個編號,每一個進程按編號遞增的順序請求資源,釋放則相反(破壞環路等待條件)
  5. 超時放棄資源:當請求超時後,線程放棄執行,從而釋放自己所佔用的資源。
  6. 對線程狀態進行監控,發現死鎖後通過剝奪資源或撤銷線程等方式解除死鎖。

但是上述解決死鎖的方法基本上都是以損害系統性能和正常運行秩序的方式來實現的。因此我們在進行程序設計時,需要注意儘量避免死鎖的產生。

7.const和define的區別?

答:對於define,其作用階段是在編譯階段,在編譯程序時,被define關鍵詞修飾的詞語會先被替換,然後才進行編譯。在程序運行階段,已經沒有define參與運行了。
而const也常用於修飾常量,其修飾的常量時只讀的,不可更改。與define不同的是,const所修飾的就是一個變量,其在程序運行時也發揮作用。
const與define相比,其優點在於:

  1. const常量有數據類型,而宏常量沒有數據類型。編譯器可以對前者進行類型安全檢查。而對後者只進行字符替換,沒有類型安全檢查,並且在字符替換可能會產生意料不到的錯誤。
  2. 有些集成化的調試工具可以對const常量進行調試,但是不能對宏常量進行調試。
  3. const可節省空間,避免不必要的內存分配,提高效率,而define在賦值的時候,可能會對同一個常量多次賦值,增加了內存。

8.對於一個頻繁使用的短小函數如何實現比較好?

答:對於C語言來說,採用宏函數的方法來實現。
對於C++來說,採用內聯函數inline來實現。
其思想都是以代碼存儲空間爲代價,減少由於函數調用而產生的時間上、內存上的開支。
內聯函數相較於宏函數來說,宏定義一般不進行參數類型檢查,內聯函數會進行類型檢查,更加安全。且宏是由預處理器對宏進行替代,編譯器接觸到的已經是替代後的代碼,而內聯函數是通過編譯器控制的,由編譯器控制將內聯函數的代碼插入到響應的語句段中。

9.局部變量和全局變量的區別?

答:建議從變量的生命期、作用域、存儲域等方面來比較:

  1. 生命期來說,全局變量的生命期是從程序開始到程序結束,隨程序的銷燬而銷燬;局部變量的生命期只有函數內部,隨着函數的結束,局部變量被銷燬。
  2. 作用域來說,全局變量的作用域爲整個程序,局部變量的作用域只有當前函數。
  3. 存儲域來說,全局變量存儲在全局區(靜態區),而局部變量存儲在棧區。

10.函數的參數存放在哪裏?

答:函數的參數存放在棧區。

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