360嵌入式軟開面經,純八股文
在程序員求職的賽道上,嵌入式開發崗位憑借其獨特魅力與廣闊前景,吸引著無數開發者投身其中。當下,嵌入式技術深度融入智能硬件、物聯網、汽車電子等熱門領域,薪資待遇更是相當誘人,對于那些不想深陷后端開發激烈競爭的小伙伴而言,無疑是個絕佳選擇。而 360,這家在互聯網安全領域聲名赫赫的企業,如今也在嵌入式開發領域持續發力,對相關人才求賢若渴。
其面試流程自然備受關注,尤其是一面,往往是決定能否順利通關的關鍵。今天,咱們就聚焦一場真實的 360 嵌入式軟開一面,令人意外的是,此次面試幾乎全是 “八股文” 式題目。所謂 “八股文”,涵蓋了 C 語言基礎、數據結構、操作系統、硬件通信等嵌入式開發必備知識板塊,精準考察候選人的知識儲備與專業素養。這些題目看似常規,實則暗藏玄機,要想完美作答,絕非易事。接下來,就讓我們一同走進這場面經,探尋嵌入式開發面試的奧秘,為你的求職之路添磚加瓦 。
1.Wi-Fi關聯是怎么做的了解過嗎(看我有過Wi-Fi路由器開發的項目)
Wi-Fi關聯是指無線設備(如手機、電腦)與Wi-Fi接入點之間建立連接的過程。了解一些基本概念可以幫助理解關聯的過程:
- SSID(Service Set Identifier):也稱為Wi-Fi網絡名稱,是一個用于標識無線網絡的字符串。
- BSSID(Basic Service Set Identifier):唯一標識一個Wi-Fi接入點的物理地址。
- 信道(Channel):Wi-Fi使用不同的頻段和信道進行通信。
當設備要連接到某個Wi-Fi網絡時,它會執行以下步驟:
- 掃描:設備會掃描附近可用的Wi-Fi網絡,并獲取它們的SSID、BSSID和信號強度等信息。
- 選擇網絡:根據一定算法,設備選擇要連接的目標網絡。
- 關聯請求:設備向選定的目標網絡發送關聯請求。該請求包含設備自身的MAC地址、認證信息等。
- 認證與加密:接入點收到關聯請求后,根據預先設置好的安全機制(如WPA2密碼),進行認證和加密過程以驗證設備身份。
- 分配IP地址:認證成功后,接入點將為設備分配一個IP地址,使其能夠在局域網中進行通信。
- 關聯確認:接入點向設備發送關聯確認消息,表示連接已建立。
通過這些步驟,設備與Wi-Fi接入點成功關聯,可以開始進行數據傳輸。整個過程的具體細節和實現方式可能會因不同的Wi-Fi標準(如802.11n、802.11ac)和設備操作系統而有所差異。
2. TCP保證可靠性有哪些措施
TCP(傳輸控制協議)通過以下幾種措施來保證可靠性:
- 序列號和確認應答:每個TCP報文段都會分配一個唯一的序列號,接收端通過發送確認應答來告知發送端已成功接收到數據。
- 超時重傳:發送端在發送數據后會啟動一個定時器,如果在規定時間內沒有收到確認應答,就會重新發送該數據段。
- 滑動窗口:TCP使用滑動窗口機制來實現流量控制和擁塞控制。接收端通過通告窗口大小來告訴發送端可以接收的數據量,從而避免過多的數據堆積。
- 丟包重傳:如果發生丟包,接收方可以通過請求重傳丟失的數據段來實現可靠性。
- 流量控制:TCP使用滑動窗口機制來進行流量控制,根據接收方的處理能力和網絡狀況調整發送速率,避免過載造成數據丟失或延遲。
- 擁塞控制:TCP通過擁塞窗口、慢啟動、擁塞避免等算法來感知并控制網絡擁塞情況,以避免過度擁塞導致網絡性能下降。
這些機制共同確保了TCP的可靠性,使得數據在傳輸過程中可以準確無誤地被接收方接收到。
4. 如何用C語言實現大小端
在C語言中,可以使用聯合體(union)來實現大小端的轉換。
首先,定義一個32位無符號整型數(例如uint32_t),然后定義一個聯合體,該聯合體包含一個該類型的成員和一個4字節大小的字符數組。如下所示:
#include <stdio.h>
#include <stdint.h>
typedef union {
uint32_t value;
unsigned char bytes[4];
} EndianConverter;接下來,我們可以編寫函數來判斷當前系統是大端還是小端。在小端系統中,最低有效字節存儲在最低地址上;而在大端系統中,最高有效字節存儲在最低地址上。
int isLittleEndian() {
EndianConverter converter;
converter.value = 1;
return converter.bytes[0] == 1; // 如果第一個字節為1,則為小端
}你也可以編寫函數來進行大小端轉換:
uint32_t swapEndian(uint32_t value) {
EndianConverter converter;
converter.value = value;
unsigned char temp = converter.bytes[0];
converter.bytes[0] = converter.bytes[3];
converter.bytes[3] = temp;
temp = converter.bytes[1];
converter.bytes[1] = converter.bytes[2];
converter.bytes[2] = temp;
return converter.value;
}這樣就可以通過調用 isLittleEndian() 函數來判斷系統是否為小端,并且通過調用 swapEndian() 函數來實現大小端之間的轉換。
5. 802.11ax和802.11ac/n這些有什么區別
02.11ax(Wi-Fi 6)和802.11ac/n(Wi-Fi 5)都是無線局域網(WLAN)的標準。它們之間有以下區別:
- 性能:802.11ax提供更高的數據傳輸速度和更大的容量,比802.11ac/n更快。它支持更多同時連接設備,并且可以在擁擠的網絡環境中提供更穩定的性能。
- 頻段利用率:802.11ax引入了一些新技術,如OFDMA(正交頻分多址)和MU-MIMO(多用戶多輸入多輸出),可以將信道劃分為較小的子信道并同時傳輸給多個設備,以提高頻段利用率。
- 網絡效率:802.11ax使用了一些優化算法,如目標喚醒時間(TWT)和空閑狀態電源管理,以降低功耗并延長設備電池壽命。
- 向后兼容性:雖然兩者不直接兼容,但大部分現有設備仍可通過向下兼容模式與802.11ax或802.11ac/n網絡通信。
6. 進程和線程的區別
進程和線程是操作系統中兩個重要的概念,它們都是并發執行任務的方式,但有一些關鍵的區別:
- 調度:進程是操作系統分配資源和調度的基本單位,每個進程都有獨立的地址空間、內存和其他系統資源。而線程是在進程內部創建和調度的,多個線程共享同一個進程的資源。
- 資源開銷:由于每個進程都具有獨立的資源,因此創建和銷毀進程時會產生較大的開銷。而線程相對較輕量級,在同一個進程中創建和切換線程時開銷較小。
- 通信與同步:不同進程之間通信比較復雜,需要使用特定機制(如管道、消息隊列等)。而在同一個進程內部,線程可以直接通過共享內存進行通信,并且可以使用鎖等機制實現線程間的同步。
- 容錯性:由于每個進程有獨立的地址空間,所以一個進程崩潰不會影響其他進程。但在多線程情況下,一個線程崩潰可能會導致整個進程崩潰。
7. 多進程編程實現
在多進程編程中,可以使用以下方法來實現:
- 使用操作系統提供的多進程API,例如fork()函數。通過調用fork()函數,父進程創建一個子進程,子進程會完全復制父進程的代碼和數據,并從fork()函數處開始執行。這樣就可以實現多個并行運行的進程。
- 使用Python中的multiprocessing模塊。該模塊提供了方便的接口來創建和管理多個子進程。你可以使用Process類來創建新的進程對象,并使用start()方法啟動它們。
- 使用線程池或進程池。線程池或進程池是一種管理并發任務的方式,通過預先創建一定數量的線程或進程,在需要時將任務分配給它們執行。這種方式可以避免頻繁地創建和銷毀線程或進程帶來的開銷。
- 利用消息隊列進行通信。不同的進程之間可以通過共享消息隊列來進行通信和協調工作。一個進程可以將消息發送到隊列中,其他相關進程則可以從隊列中讀取并處理這些消息。
8. MCS是什么(沒料到嵌入式還問物理層)
MCS通常是指"Minecraft Coder Pack",是一個用于修改游戲《Minecraft》的工具包。它允許開發者對游戲進行自定義修改和編程。通過使用MCS,開發者可以創建新的游戲內容、添加新的功能和改變游戲的行為。這個工具包提供了一系列API和庫,方便開發者進行修改和擴展。
9. C語言中如何防止同一個.h文件被重復 #include
在C語言中,可以使用預處理指令 #ifndef、#define 和 #endif 來防止同一個頭文件被重復包含。具體步驟如下:
- 1.在頭文件的開頭加入以下代碼:
#ifndef HEADER_FILE_NAME_H
#define HEADER_FILE_NAME_H
// 頭文件的內容
#endif- 2.替換其中的 HEADER_FILE_NAME_H 為你自定義的宏名,一般以頭文件名全大寫并添加后綴 _H。
- 3.這樣,在每次包含該頭文件之前,預處理器會先檢查是否已經定義了該宏。如果沒有定義,則繼續執行 #define 和后續代碼;如果已經定義了該宏,則跳過整個頭文件的內容。
通過這種方式,可以確保同一個頭文件在同一個源代碼中只被包含一次,避免了重復聲明和定義導致的編譯錯誤。
10. 動態鏈接和靜態鏈接分別是什么
動態鏈接和靜態鏈接是軟件開發中常用的兩種鏈接方式。
靜態鏈接是將程序所需的所有庫文件在編譯時直接嵌入到可執行文件中。這意味著生成的可執行文件獨立于外部庫,可以單獨運行。靜態鏈接的優點是簡單、方便,不需要額外的依賴,但缺點是可執行文件較大。
動態鏈接是在程序運行時,由操作系統加載所需的共享庫并進行鏈接。相比于靜態鏈接,動態鏈接生成的可執行文件較小,并且多個程序可以共享同一個動態庫實例,減少內存占用。此外,如果共享庫更新了,只需要替換對應的庫文件即可。
11. 對指針的理解
指針是C++中的一種數據類型,它存儲了一個變量的內存地址。通過指針,可以直接訪問或修改該內存地址上的數據。
在C++中,通過使用取地址運算符"&"可以獲取變量的內存地址,并將其賦給相應的指針變量。例如:
int num = 10;
int* ptr = # // 將num的地址賦給ptr可以使用解引用運算符"*"來訪問指針所指向的值。例如:
cout << *ptr; // 輸出ptr所指向的值(即num的值)還可以進行指針間的操作,如指針之間的賦值、比較等。
需要注意的是,在使用指針時要確保指針有效且不為空,避免空指針異常和未定義行為。
指針在C++中廣泛用于動態內存分配、數組操作、函數傳遞參數等場景,是C++中重要且強大的特性之一。
12. 函數指針怎么使用 有什么作用
函數指針是指向函數的指針變量。它可以用來存儲函數的地址,使得我們可以通過函數指針來調用對應的函數。
要聲明一個函數指針,可以使用以下語法:
返回類型 (*指針變量名)(參數列表);例如,假設有一個名為 add 的函數,它接受兩個整數參數并返回它們的和。我們可以聲明一個與該函數匹配的函數指針如下:
int (*ptr)(int, int);然后,我們可以將 add 函數的地址賦給這個函數指針:
ptr = &add;或者簡寫為:
ptr = add;現在,我們就可以通過函數指針來調用 add 函數了:
int result = ptr(3, 4); // 調用 add 函數使用函數指針的好處之一是它允許動態地選擇和調用不同的函數。這在編程中很有用,特別是當需要根據運行時條件決定執行哪個具體的函數時。
此外,函數指針也常用于作為回調機制,在某些情況下允許將一個函數傳遞給另一個函數作為參數,并在需要時進行調用。
13. TCP/IP網絡模型一共幾層 哪幾層
TCP/IP網絡模型一共有四層,它們是:
- 網絡接口層(Network Interface Layer):負責處理與物理網絡介質的通信,如以太網、Wi-Fi等。
- 網際層(Internet Layer):提供了數據在不同網絡之間的路由和轉發功能,使用IP協議進行尋址和傳輸。
- 傳輸層(Transport Layer):提供端到端的數據傳輸服務,常用的協議有TCP (Transmission Control Protocol) 和UDP (User Datagram Protocol)。
- 應用層(Application Layer):提供各種應用程序與網絡通信的接口,包括HTTP、FTP、SMTP等協議。
這些層級組成了TCP/IP網絡模型,用于實現互聯網中不同設備之間的通信。
14. ARP協議具體干什么的
ARP(Address Resolution Protocol,地址解析協議)是一種用于將IP地址轉換為物理MAC地址的協議。在網絡通信中,數據包需要知道目標主機的MAC地址才能正確傳遞。而ARP協議就是用來通過發送廣播請求獲取一個目標IP對應的MAC地址。
具體來說,當一個主機需要與另一個主機進行通信時,它會首先檢查自己的本地ARP緩存表,看是否已經有了目標IP對應的MAC地址記錄。如果沒有,則會發送一個ARP請求廣播到局域網上的所有主機,詢問哪個主機擁有該IP地址對應的MAC地址。收到這個請求的主機會檢查自己的IP地址,并向發出請求的主機發送一個ARP響應包含其自己的MAC地址。
一旦發起方收到了目標主機返回的ARP響應包含目標主機的MAC地址后,它就可以使用這個MAC地址將數據包直接發送給目標主機,從而建立起有效通信。


























