嵌入式筆試面試題目系列(匯總)
本系列按類別對題目進(jìn)行分類整理,這樣有利于大家對嵌入式的筆試面試考察框架有一個完整的理解。
一、進(jìn)程與線程
1、什么是進(jìn)程、線程,有什么區(qū)別?
進(jìn)程是資源(CPU、內(nèi)存等)分配的基本單位,線程是CPU調(diào)度和分配的基本單位(程序執(zhí)行的最小單位)。同一時間,如果CPU是單核,只有一個進(jìn)程在執(zhí)行,所謂的并發(fā)執(zhí)行,也是順序執(zhí)行,只不過由于切換速度太快,你以為這些進(jìn)程在同步執(zhí)行而已。多核CPU可以同一時間點有多個進(jìn)程在執(zhí)行。
2、多進(jìn)程、多線程的優(yōu)缺點
說明:一個進(jìn)程由進(jìn)程控制塊、數(shù)據(jù)段、代碼段組成,進(jìn)程本身不可以運行程序,而是像一個容器一樣,先創(chuàng)建出一個主線程,分配給主線程一定的系統(tǒng)資源,這時候就可以在主線程開始實現(xiàn)各種功能。當(dāng)我們需要實現(xiàn)更復(fù)雜的功能時,可以在主線程里創(chuàng)建多個子線程,多個線程在同一個進(jìn)程里,利用這個進(jìn)程所擁有的系統(tǒng)資源合作完成某些功能。
優(yōu)缺點:1)一個進(jìn)程死了不影響其他進(jìn)程,一個線程崩潰很可能影響到它本身所處的整個進(jìn)程。2) 創(chuàng)建多進(jìn)程的系統(tǒng)花銷大于創(chuàng)建多線程。3)多進(jìn)程通訊因為需要跨越進(jìn)程邊界,不適合大量數(shù)據(jù)的傳送,適合小數(shù)據(jù)或者密集數(shù)據(jù)的傳送。多線程無需跨越進(jìn)程邊界,適合各線程間大量數(shù)據(jù)的傳送。并且多線程可以共享同一進(jìn)程里的共享內(nèi)存和變量。
3、什么時候用進(jìn)程,什么時候用線程
1)創(chuàng)建和銷毀較頻繁使用線程,因為創(chuàng)建進(jìn)程花銷大。2)需要大量數(shù)據(jù)傳送使用線程,因為多線程切換速度快,不需要跨越進(jìn)程邊界。3)安全穩(wěn)定選進(jìn)程;快速頻繁選線程;
4、多進(jìn)程、多線程同步(通訊)的方法
進(jìn)程間通訊:
(1)有名管道/無名管道(2)信號(3)共享內(nèi)存(4)消息隊列(5)信號量(6)socket
線程通訊(鎖):
(1)信號量(2)讀寫鎖(3)條件變量(4)互斥鎖(5)自旋鎖
5、進(jìn)程線程的狀態(tài)轉(zhuǎn)換圖
(1)就緒狀態(tài):進(jìn)程已獲得除CPU外的所有必要資源,只等待CPU時的狀態(tài)。一個系統(tǒng)會將多個處于就緒狀態(tài)的進(jìn)程排成一個就緒隊列。
(2)執(zhí)行狀態(tài):進(jìn)程已獲CPU,正在執(zhí)行。單處理機系統(tǒng)中,處于執(zhí)行狀態(tài)的進(jìn)程只一個;多處理機系統(tǒng)中,有多個處于執(zhí)行狀態(tài)的進(jìn)程。
(3)阻塞狀態(tài):正在執(zhí)行的進(jìn)程由于某種原因而暫時無法繼續(xù)執(zhí)行,便放棄處理機而處于暫停狀態(tài),即進(jìn)程執(zhí)行受阻。(這種狀態(tài)又稱等待狀態(tài)或封鎖狀態(tài))
通常導(dǎo)致進(jìn)程阻塞的典型事件有:請求I/O,申請緩沖空間等。
一般,將處于阻塞狀態(tài)的進(jìn)程排成一個隊列,有的系統(tǒng)還根據(jù)阻塞原因不同把這些阻塞集成排成多個隊列。

(1) 就緒→執(zhí)行
處于就緒狀態(tài)的進(jìn)程,當(dāng)進(jìn)程調(diào)度程序為之分配了處理機后,該進(jìn)程便由就緒狀態(tài)轉(zhuǎn)變成執(zhí)行狀態(tài)。
(2) 執(zhí)行→就緒
處于執(zhí)行狀態(tài)的進(jìn)程在其執(zhí)行過程中,因分配給它的一個時間片已用完而不得不讓出處理機,于是進(jìn)程從執(zhí)行狀態(tài)轉(zhuǎn)變成就緒狀態(tài)。
(3) 執(zhí)行→阻塞
正在執(zhí)行的進(jìn)程因等待某種事件發(fā)生而無法繼續(xù)執(zhí)行時,便從執(zhí)行狀態(tài)變成阻塞狀態(tài)。
(4) 阻塞→就緒
處于阻塞狀態(tài)的進(jìn)程,若其等待的事件已經(jīng)發(fā)生,于是進(jìn)程由阻塞狀態(tài)轉(zhuǎn)變?yōu)榫途w狀態(tài)。
6、父進(jìn)程、子進(jìn)程
父進(jìn)程調(diào)用fork()以后,克隆出一個子進(jìn)程,子進(jìn)程和父進(jìn)程擁有相同內(nèi)容的代碼段、數(shù)據(jù)段和用戶堆棧。父進(jìn)程和子進(jìn)程誰先執(zhí)行不一定,看CPU。所以我們一般我們會設(shè)置父進(jìn)程等待子進(jìn)程執(zhí)行完畢。
7、說明什么是上下文切換?
你可以有很多角度,有進(jìn)程上下文,有中斷上下文。
進(jìn)程上下文:一個進(jìn)程在執(zhí)行的時候,CPU的所有寄存器中的值、進(jìn)程的狀態(tài)以及堆棧中的內(nèi)容,當(dāng)內(nèi)核需要切換到另一個進(jìn)程時,它需要保存當(dāng)前進(jìn)程的所有狀態(tài),即保存當(dāng)前進(jìn)程的進(jìn)程上下文,以便再次執(zhí)行該進(jìn)程時,能夠恢復(fù)切換時的狀態(tài),繼續(xù)執(zhí)行。
中斷上下文:由于觸發(fā)信號,導(dǎo)致CPU中斷當(dāng)前進(jìn)程,轉(zhuǎn)而去執(zhí)行另外的程序。那么當(dāng)前進(jìn)程的所有資源要保存,比如堆棧和指針。保存過后轉(zhuǎn)而去執(zhí)行中斷處理程序,快讀執(zhí)行完畢返回,返回后恢復(fù)上一個進(jìn)程的資源,繼續(xù)執(zhí)行。這就是中斷的上下文。
二、C/C++題目
1、new和malloc
做嵌入式,對于內(nèi)存是十分在意的,因為可用內(nèi)存有限,所以嵌入式筆試面試題目,內(nèi)存的題目高頻。
1)malloc和free是c++/c語言的庫函數(shù),需要頭文件支持stdlib.h;new和delete是C++的關(guān)鍵字,不需要頭文件,需要編譯器支持;
2)使用new操作符申請內(nèi)存分配時,無需指定內(nèi)存塊的大小,編譯器會根據(jù)類型信息自行計算。而malloc則需要顯式地支持所需內(nèi)存的大小。
3)new操作符內(nèi)存分配成功時,返回的是對象類型的指針,類型嚴(yán)格與對象匹配,無需進(jìn)行類型轉(zhuǎn)換,故new是符合類型安全性的操作符。而malloc內(nèi)存分配成功則是返回void*,需要通過強制類型轉(zhuǎn)換將void*指針轉(zhuǎn)換成我們需要的類型。
4)new內(nèi)存分配失敗時,會拋出bad_alloc異常。malloc分配內(nèi)存失敗時返回NULL。
2、在1G內(nèi)存的計算機中能否malloc(1.2G)?為什么?(2021浙江大華二面問題)
答:是有可能申請1.2G的內(nèi)存的。
解析:回答這個問題前需要知道m(xù)alloc的作用和原理,應(yīng)用程序通過malloc函數(shù)可以向程序的虛擬空間申請一塊虛擬地址空間,與物理內(nèi)存沒有直接關(guān)系,得到的是在虛擬地址空間中的地址,之后程序運行所提供的物理內(nèi)存是由操作系統(tǒng)完成的。
3 、extern”C” 的作用
我們可以在C++中使用C的已編譯好的函數(shù)模塊,這時候就需要用到extern”C”。也就是extern“C” 都是在c++文件里添加的。
extern在鏈接階段起作用(四大階段:預(yù)處理--編譯--匯編--鏈接)。
4、strcat、strncat、strcmp、strcpy哪些函數(shù)會導(dǎo)致內(nèi)存溢出?如何改進(jìn)?(2021浙江大華二面問題)
strcpy函數(shù)會導(dǎo)致內(nèi)存溢出。
strcpy拷貝函數(shù)不安全,他不做任何的檢查措施,也不判斷拷貝大小,不判斷目的地址內(nèi)存是否夠用。
- char *strcpy(char *strDest,const char *strSrc)
strncpy拷貝函數(shù),雖然計算了復(fù)制的大小,但是也不安全,沒有檢查目標(biāo)的邊界。
- strncpy(dest, src, sizeof(dest));
strncpy_s是安全的
strcmp(str1,str2),是比較函數(shù),若str1=str2,則返回零;若str1
strncat()主要功能是在字符串的結(jié)尾追加n個字符。
- char * strncat(char *dest, const char *src, size_t n);
strcat()函數(shù)主要用來將兩個char類型連接。例如:
- char d[20]="Golden";
- char s[20]="View";
- strcat(d,s);
- //打印d
- printf("%s",d);
輸出 d 為 GoldenView (中間無空格)
延伸:
memcpy拷貝函數(shù),它與strcpy的區(qū)別就是memcpy可以拷貝任意類型的數(shù)據(jù),strcpy只能拷貝字符串類型。
memcpy 函數(shù)用于把資源內(nèi)存(src所指向的內(nèi)存區(qū)域)拷貝到目標(biāo)內(nèi)存(dest所指向的內(nèi)存區(qū)域);有一個size變量控制拷貝的字節(jié)數(shù);
函數(shù)原型:
- void *memcpy(void *dest, void *src, unsigned int count);
5 、static的用法(定義和用途)(必考)
1)用static修飾局部變量:使其變?yōu)殪o態(tài)存儲方式(靜態(tài)數(shù)據(jù)區(qū)),那么這個局部變量在函數(shù)執(zhí)行完成之后不會被釋放,而是繼續(xù)保留在內(nèi)存中。
2)用static修飾全局變量:使其只在本文件內(nèi)部有效,而其他文件不可連接或引用該變量。
3)用static修飾函數(shù):對函數(shù)的連接方式產(chǎn)生影響,使得函數(shù)只在本文件內(nèi)部有效,對其他文件是不可見的(這一點在大工程中很重要很重要,避免很多麻煩,很常見)。這樣的函數(shù)又叫作靜態(tài)函數(shù)。使用靜態(tài)函數(shù)的好處是,不用擔(dān)心與其他文件的同名函數(shù)產(chǎn)生干擾,另外也是對函數(shù)本身的一種保護(hù)機制。
6、const的用法(定義和用途)(必考)
const主要用來修飾變量、函數(shù)形參和類成員函數(shù):
1)用const修飾常量:定義時就初始化,以后不能更改。
2)用const修飾形參:func(const int a){};該形參在函數(shù)里不能改變
3)用const修飾類成員函數(shù):該函數(shù)對成員變量只能進(jìn)行只讀操作,就是const類成員函數(shù)是不能修改成員變量的數(shù)值的。
被const修飾的東西都受到強制保護(hù),可以預(yù)防意外的變動,能提高程序的健壯性。
參考一個大佬的回答:
我只要一聽到被面試者說:"const意味著常數(shù)",我就知道我正在和一個業(yè)余者打交道。去年Dan Saks已經(jīng)在他的文章里完全概括了const的所有用法,因此ESP(譯者:Embedded Systems Programming)的每一位讀者應(yīng)該非常熟悉const能做什么和不能做什么.如果你從沒有讀到那篇文章,只要能說出const意味著"只讀"就可以了。盡管這個答案不是完全的答案,但我接受它作為一個正確的答案。如果應(yīng)試者能正確回答這個問題,我將問他一個附加的問題:下面的聲明都是什么意思?
- const int a;
- int const a;
- const int *a;
- int * const a;
- int const * a const;
前兩個的作用是一樣,a是一個常整型數(shù)。
第三個意味著a是一個指向常整型數(shù)的指針(也就是,整型數(shù)是不可修改的,但指針可以)。
第四個意思a是一個指向整型數(shù)的常指針(也就是說,指針指向的整型數(shù)是可以修改的,但指針是不可修改的)。
最后一個意味著a是一個指向常整型數(shù)的常指針(也就是說,指針指向的整型數(shù)是不可修改的,同時指針也是不可修改的)。
7、volatile作用和用法
一個定義為volatile的變量是說這變量可能會被意想不到地改變,這樣,編譯器就不會去假設(shè)這個變量的值了。精確地說就是,優(yōu)化器在用到這個變量時必須每次都小心地重新讀取這個變量在內(nèi)存中的值,而不是使用保存在寄存器里的備份(雖然讀寫寄存器比讀寫內(nèi)存快)。
回答不出這個問題的人是不會被雇傭的。這是區(qū)分C程序員和嵌入式系統(tǒng)程序員的最基本的問題。搞嵌入式的家伙們經(jīng)常同硬件、中斷、RTOS等等打交道,所有這些都要求用到volatile變量。不懂得volatile的內(nèi)容將會帶來災(zāi)難。
以下幾種情況都會用到volatile:
1、并行設(shè)備的硬件寄存器(如:狀態(tài)寄存器)2、一個中斷服務(wù)子程序中會訪問到的非自動變量3、多線程應(yīng)用中被幾個任務(wù)共享的變量
8、const常量和#define的區(qū)別(編譯階段、安全性、內(nèi)存占用等)
用#define max 100 ; 定義的常量是沒有類型的(不進(jìn)行類型安全檢查,可能會產(chǎn)生意想不到的錯誤),所給出的是一個立即數(shù),編譯器只是把所定義的常量值與所定義的常量的名字聯(lián)系起來,define所定義的宏變量在預(yù)處理階段的時候進(jìn)行替換,在程序中使用到該常量的地方都要進(jìn)行拷貝替換;
用const int max = 255 ; 定義的常量有類型(編譯時會進(jìn)行類型檢查)名字,存放在內(nèi)存的靜態(tài)區(qū)域中,在編譯時確定其值。在程序運行過程中const變量只有一個拷貝,而#define所定義的宏變量卻有多個拷貝,所以宏定義在程序運行過程中所消耗的內(nèi)存要比const變量的大得多
9、變量的作用域(全局變量和局部變量)
全局變量:在所有函數(shù)體的外部定義的,程序的所在部分(甚至其它文件中的代碼)都可以使用。全局變量不受作用域的影響(也就是說,全局變量的生命期一直到程序的結(jié)束)。
局部變量:出現(xiàn)在一個作用域內(nèi),它們是局限于一個函數(shù)的。局部變量經(jīng)常被稱為自動變量,因為它們在進(jìn)入作用域時自動生成,離開作用域時自動消失。關(guān)鍵字auto可以顯式地說明這個問題,但是局部變量默認(rèn)為auto,所以沒有必要聲明為auto。
局部變量可以和全局變量重名,在局部變量作用域范圍內(nèi),全局變量失效,采用的是局部變量的值。
10、sizeof 與strlen (字符串,數(shù)組)
1.如果是數(shù)組
- #include<stdio.h>
- int main()
- {
- int a[5]={1,2,3,4,5};
- printf(“sizeof 數(shù)組名=%d\n”,sizeof(a));
- printf(“sizeof *數(shù)組名=%d\n”,sizeof(*a));
- }
運行結(jié)果
- sizeof 數(shù)組名=20
- sizeof *數(shù)組名=4
2.如果是指針,sizeof只會檢測到是指針的類型,指針都是占用4個字節(jié)的空間(32位機)。
sizeof是什么?是一個操作符,也是關(guān)鍵字,就不是一個函數(shù),這和strlen()不同,strlen()是一個函數(shù)。
那么sizeof的作用是什么?返回一個對象或者類型所占的內(nèi)存字節(jié)數(shù)。我們會對sizeof()中的數(shù)據(jù)或者指針做運算嗎?基本不會。例如sizeof(1+2.0),直接檢測到其中類型是double,即是sizeof(double) = 8。如果是指針,sizeof只會檢測到是指針的類型,指針都是占用4個字節(jié)的空間(32位機)。
- char *p = "sadasdasd";
- sizeof(p):4
- sizeof(*p):1//指向一個char類型的
除非使用strlen(),僅對字符串有效,直到'\0'為止了,計數(shù)結(jié)果不包括\0。
要是非要使用sizeof來得到指向內(nèi)容的大小,就得使用數(shù)組名才行, 如
- char a[10];
- sizeof(a):10 //檢測到a是一個數(shù)組的類型。
關(guān)于strlen(),它是一個函數(shù),考察的比較簡單:
- strlen “\n\t\tag\AAtang”
答案:11
11、經(jīng)典的sizeof(struct)和sizeof(union)內(nèi)存對齊
內(nèi)存對齊作用:
1.平臺原因(移植原因):不是所有的硬件平臺都能訪問任意地址上的任意數(shù)據(jù)的;某些硬件平臺只能在某些地址處取某些特定類型的數(shù)據(jù),否則拋出硬件異常。
2.性能原因:數(shù)據(jù)結(jié)構(gòu)(尤其是棧)應(yīng)該盡可能地在自然邊界上對齊。原因在于,為了訪問未對齊的內(nèi)存,處理器需要作兩次內(nèi)存訪問;而對齊的內(nèi)存訪問僅需要一次訪問。
結(jié)構(gòu)體struct內(nèi)存對齊的3大規(guī)則:
1.對于結(jié)構(gòu)體的各個成員,第一個成員的偏移量是0,排列在后面的成員其當(dāng)前偏移量必須是當(dāng)前成員類型的整數(shù)倍;
2.結(jié)構(gòu)體內(nèi)所有數(shù)據(jù)成員各自內(nèi)存對齊后,結(jié)構(gòu)體本身還要進(jìn)行一次內(nèi)存對齊,保證整個結(jié)構(gòu)體占用內(nèi)存大小是結(jié)構(gòu)體內(nèi)最大數(shù)據(jù)成員的最小整數(shù)倍;
3.如程序中有#pragma pack(n)預(yù)編譯指令,則所有成員對齊以n字節(jié)為準(zhǔn)(即偏移量是n的整數(shù)倍),不再考慮當(dāng)前類型以及最大結(jié)構(gòu)體內(nèi)類型。
- #pragma pack(1)
- struct fun{
- int i;
- double d;
- char c;
- };
sizeof(fun) = 13
- struct CAT_s
- {
- int ld;
- char Color;
- unsigned short Age;
- char *Name;
- void(*Jump)(void);
- }Garfield;
1.使用32位編譯,int占4, char 占1, unsigned short 占2,char* 占4,函數(shù)指針占4個,由于是32位編譯是4字節(jié)對齊,所以該結(jié)構(gòu)體占16個字節(jié)。(說明:按幾字節(jié)對齊,是根據(jù)結(jié)構(gòu)體的最長類型決定的,這里是int是最長的字節(jié),所以按4字節(jié)對齊);
2.使用64位編譯 ,int占4, char 占1, unsigned short 占2,char* 占8,函數(shù)指針占8個,由于是64位編譯是8字節(jié)對齊(說明:按幾字節(jié)對齊,是根據(jù)結(jié)構(gòu)體的最長類型決定的,這里是函數(shù)指針是最長的字節(jié),所以按8字節(jié)對齊)所以該結(jié)構(gòu)體占24個字節(jié)。
- //64位
- struct C
- {
- double t; //8 1111 1111
- char b; //1 1
- int a; //4 0001111
- short c; //2 11000000
- };
- sizeof(C) = 24; //注意:1 4 2 不能拼在一起
char是1,然后在int之前,地址偏移量得是4的倍數(shù),所以char后面補三個字節(jié),也就是char占了4個字節(jié),然后int四個字節(jié),最后是short,只占兩個字節(jié),但是總的偏移量得是double的倍數(shù),也就是8的倍數(shù),所以short后面補六個字節(jié)
聯(lián)合體union內(nèi)存對齊的2大規(guī)則:
1.找到占用字節(jié)最多的成員;
2.union的字節(jié)數(shù)必須是占用字節(jié)最多的成員的字節(jié)的倍數(shù),而且需要能夠容納其他的成員
- //x64
- typedef union {
- long i;
- int k[5];
- char c;
- }D
要計算union的大小,首先要找到占用字節(jié)最多的成員,本例中是long,占用8個字節(jié),int k[5]中都是int類型,仍然是占用4個字節(jié)的,然后union的字節(jié)數(shù)必須是占用字節(jié)最多的成員的字節(jié)的倍數(shù),而且需要能夠容納其他的成員,為了要容納k(20個字節(jié)),就必須要保證是8的倍數(shù)的同時還要大于20個字節(jié),所以是24個字節(jié)。
引申:位域(大疆筆試題)
C語言允許在一個結(jié)構(gòu)體中以位為單位來指定其成員所占內(nèi)存長度,這種以位為單位的成員稱為“位段”或稱“位域”( bit field) 。利用位段能夠用較少的位數(shù)存儲數(shù)據(jù)。一個位段必須存儲在同一存儲單元中,不能跨兩個單元。如果第一個單元空間不能容納下一個位段,則該空間不用,而從下一個單元起存放該位段。
1.位段聲明和結(jié)構(gòu)體類似
2.位段的成員必須是int、unsigned int、signed int
3.位段的成員名后邊有一個冒號和一個數(shù)字
- typedef struct_data{
- char m:3;
- char n:5;
- short s;
- union{
- int a;
- char b;
- };
- int h;
- }_attribute_((packed)) data_t;
答案12
m和n一起,剛好占用一個字節(jié)內(nèi)存,因為后面是short類型變量,所以在short s之前,應(yīng)該補一個字節(jié)。所以m和n其實是占了兩個字節(jié)的,然后是short兩個個字節(jié),加起來就4個字節(jié),然后聯(lián)合體占了四個字節(jié),總共8個字節(jié)了,最后int h占了四個字節(jié),就是12個字節(jié)了
attribute((packed)) 取消對齊
GNU C的一大特色就是__attribute__機制。__attribute__可以設(shè)置函數(shù)屬性(Function Attribute)、變量屬性(Variable Attribute)和類型屬性(Type Attribute)。
__attribute__書寫特征是:__attribute__前后都有兩個下劃線,并且后面會緊跟一對括弧,括弧里面是相應(yīng)的__attribute__參數(shù)。
跨平臺通信時用到。不同平臺內(nèi)存對齊方式不同。如果使用結(jié)構(gòu)體進(jìn)行平臺間的通信,會有問題。例如,發(fā)送消息的平臺上,結(jié)構(gòu)體為24字節(jié),接受消息的平臺上,此結(jié)構(gòu)體為32字節(jié)(只是隨便舉個例子),那么每個變量對應(yīng)的值就不對了。
不同框架的處理器對齊方式會有不同,這個時候不指定對齊的話,會產(chǎn)生錯誤結(jié)果
12、inline函數(shù)
在C語言中,如果一些函數(shù)被頻繁調(diào)用,不斷地有函數(shù)入棧,即函數(shù)棧,會造成棧空間或棧內(nèi)存的大量消耗。為了解決這個問題,特別的引入了inline修飾符,表示為內(nèi)聯(lián)函數(shù)。
大多數(shù)的機器上,調(diào)用函數(shù)都要做很多工作:調(diào)用前要先保存寄存器,并在返回時恢復(fù),復(fù)制實參,程序還必須轉(zhuǎn)向一個新位置執(zhí)行C++中支持內(nèi)聯(lián)函數(shù),其目的是為了提高函數(shù)的執(zhí)行效率,用關(guān)鍵字 inline 放在函數(shù)定義(注意是定義而非聲明)的前面即可將函數(shù)指定為內(nèi)聯(lián)函數(shù),內(nèi)聯(lián)函數(shù)通常就是將它在程序中的每個調(diào)用點上“內(nèi)聯(lián)地”展開。
內(nèi)聯(lián)是以代碼膨脹(復(fù)制)為代價,僅僅省去了函數(shù)調(diào)用的開銷,從而提高函數(shù)的執(zhí)行效率。
13、內(nèi)存四區(qū),什么變量分別存儲在什么區(qū)域,堆上還是棧上。


文字常量區(qū),叫.rodata,不可以改變,改變會導(dǎo)致段錯誤
- int a0=1;
- static int a1;
- const static a2=0;
- extern int a3;
- void fun(void)
- {
- int a4;
- volatile int a5;
- return;
- }
a0 :全局初始化變量;生命周期為整個程序運行期間;作用域為所有文件;存儲位置為data段。
a1 :全局靜態(tài)未初始化變量;生命周期為整個程序運行期間;作用域為當(dāng)前文件;儲存位置為BSS段。
a2 :全局靜態(tài)變量
a3 :全局初始化變量;其他同a0。
a4 :局部變量;生命周期為fun函數(shù)運行期間;作用域為fun函數(shù)內(nèi)部;儲存位置為棧。
a5 :局部易變變量;
14、使用32位編譯情況下,給出判斷所使用機器大小端的方法。

聯(lián)合體方法判斷方法:利用union結(jié)構(gòu)體的從低地址開始存,且同一時間內(nèi)只有一個成員占有內(nèi)存的特性。大端儲存符合閱讀習(xí)慣。聯(lián)合體占用內(nèi)存是最大的那個,和結(jié)構(gòu)體不一樣。
a和c公用同一片內(nèi)存區(qū)域,所以更改c,必然會影響a的數(shù)據(jù)
- #include<stdio.h>
- int main(){
- union w
- {
- int a;
- char b;
- }c;
- c.a = 1;
- if(c.b == 1)
- printf("小端存儲\n");
- else
- printf("大端存儲\n");
- return 0;
- }
指針方法
通過將int強制類型轉(zhuǎn)換成char單字節(jié),p指向a的起始字節(jié)(低字節(jié))
- #include <stdio.h>
- int main ()
- {
- int a = 1;
- char *p = (char *)&a;
- if(*p == 1)
- {
- printf("小端存儲\n");
- }
- else
- {
- printf("大端存儲\n");
- }
- return 0;
- }
15、用變量a給出下面的定義
- a) 一個整型數(shù);
- b)一個指向整型數(shù)的指針;
- c)一個指向指針的指針,它指向的指針是指向一個整型數(shù);
- d)一個有10個整型的數(shù)組;
- e)一個有10個指針的數(shù)組,該指針是指向一個整型數(shù);
- f)一個指向有10個整型數(shù)數(shù)組的指針;
- g)一個指向函數(shù)的指針,該函數(shù)有一個整型參數(shù)并返回一個整型數(shù);
- h)一個有10個指針的數(shù)組,該指針指向一個函數(shù),該函數(shù)有一個整型參數(shù)并返回一個整型數(shù)
- 答案:
- a)int a
- b)int *a;
- c)int **a;
- d)int a[10];
- e)int *a [10];
- f) int a[10], *p=a;
- g)int (*a)(int)
- h) int( *a[10])(int)
16、與或非,異或。運算符優(yōu)先級
sum=a&b<
其中a=3,b=5,c=4(先加再移位再&再異或)答案4

第三章網(wǎng)絡(luò)編程
1 、TCP、UDP的區(qū)別
TCP---傳輸控制協(xié)議,提供的是面向連接、可靠的字節(jié)流服務(wù)。當(dāng)客戶和服務(wù)器彼此交換數(shù)據(jù)前,必須先在雙方之間建立一個TCP連接,之后才能傳輸數(shù)據(jù)。
UDP---用戶數(shù)據(jù)報協(xié)議,是一個簡單的面向數(shù)據(jù)報的運輸層協(xié)議。UDP不提供可靠性,它只是把應(yīng)用程序傳給IP層的數(shù)據(jù)報發(fā)送出去,但是并不能保證它們能到達(dá)目的地。
1)TCP是面向連接的,UDP是面向無連接的
2)UDP程序結(jié)構(gòu)較簡單
3)TCP是面向字節(jié)流的,UDP是基于數(shù)據(jù)報的
4)TCP保證數(shù)據(jù)正確性,UDP可能丟包
5)TCP保證數(shù)據(jù)順序到達(dá),UDP不保證
2 、TCP、UDP的優(yōu)缺點
TCP優(yōu)點:可靠穩(wěn)定
TCP的可靠體現(xiàn)在TCP在傳輸數(shù)據(jù)之前,會有三次握手來建立連接,而且在數(shù)據(jù)傳遞時,有確認(rèn)、窗口、重傳、擁塞控制機制,在數(shù)據(jù)傳完之后,還會斷開來連接用來節(jié)約系統(tǒng)資源。
TCP缺點:慢,效率低,占用系統(tǒng)資源高,易被攻擊
在傳遞數(shù)據(jù)之前要先建立連接,這會消耗時間,而且在數(shù)據(jù)傳遞時,確認(rèn)機制、重傳機制、擁塞機制等都會消耗大量時間,而且要在每臺設(shè)備上維護(hù)所有的傳輸連接。然而,每個連接都會占用系統(tǒng)的CPU,內(nèi)存等硬件資源。因為TCP有確認(rèn)機制、三次握手機制,這些也導(dǎo)致TCP容易被利用,實現(xiàn)DOS、DDOS、CC等攻擊。
UDP優(yōu)點:快,比TCP稍安全
UDP沒有TCP擁有的各種機制,是一種無狀態(tài)的傳輸協(xié)議,所以傳輸數(shù)據(jù)非常快,沒有TCP的這些機制,被攻擊利用的機會就少一些,但是也無法避免被攻擊。
UDP缺點:不可靠,不穩(wěn)定
因為沒有TCP的這些機制,UDP在傳輸數(shù)據(jù)時,如果網(wǎng)絡(luò)質(zhì)量不好,就會很容易丟包,造成數(shù)據(jù)的缺失。
3 、TCP UDP適用場景
TCP:傳輸一些對信號完整性,信號質(zhì)量有要求的信息。
UDP:對網(wǎng)絡(luò)通訊質(zhì)量要求不高時,要求網(wǎng)絡(luò)通訊速度要快的場景。
4、 TCP為什么是可靠連接?
因為tcp傳輸?shù)臄?shù)據(jù)滿足3大條件,不丟失,不重復(fù),按順序到達(dá)。
5、OSI典型網(wǎng)絡(luò)模型,簡單說說有哪些

6、三次握手、四次揮手
三次握手

1、TCP服務(wù)器進(jìn)程先創(chuàng)建傳輸控制塊TCB,時刻準(zhǔn)備接受客戶進(jìn)程的連接請求,此時服務(wù)器就進(jìn)入了LISTEN(監(jiān)聽)狀態(tài);
2、TCP客戶進(jìn)程也是先創(chuàng)建傳輸控制塊TCB,然后向服務(wù)器發(fā)出連接請求報文,這是報文首部中的同部位SYN=1,同時選擇一個初始序列號 seq=x ,此時,TCP客戶端進(jìn)程進(jìn)入了 SYN-SENT(同步已發(fā)送狀態(tài))狀態(tài)。TCP規(guī)定,SYN報文段(SYN=1的報文段)不能攜帶數(shù)據(jù),但需要消耗掉一個序號。
3、TCP服務(wù)器收到請求報文后,如果同意連接,則發(fā)出確認(rèn)報文。確認(rèn)報文中應(yīng)該 ACK=1,SYN=1,確認(rèn)號是ack=x+1,同時也要為自己初始化一個序列號 seq=y,此時,TCP服務(wù)器進(jìn)程進(jìn)入了SYN-RCVD(同步收到)狀態(tài)。這個報文也不能攜帶數(shù)據(jù),但是同樣要消耗一個序號。
4、TCP客戶進(jìn)程收到確認(rèn)后,還要向服務(wù)器給出確認(rèn)。確認(rèn)報文的ACK=1,ack=y+1,自己的序列號seq=x+1,此時,TCP連接建立,客戶端進(jìn)入ESTABLISHED(已建立連接)狀態(tài)。TCP規(guī)定,ACK報文段可以攜帶數(shù)據(jù),但是如果不攜帶數(shù)據(jù)則不消耗序號。
5、當(dāng)服務(wù)器收到客戶端的確認(rèn)后也進(jìn)入ESTABLISHED狀態(tài),此后雙方就可以開始通信了。
四次揮手

1、客戶端進(jìn)程發(fā)出連接釋放報文,并且停止發(fā)送數(shù)據(jù)。釋放數(shù)據(jù)報文首部,F(xiàn)IN=1,其序列號為seq=u(等于前面已經(jīng)傳送過來的數(shù)據(jù)的最后一個字節(jié)的序號加1),此時,客戶端進(jìn)入FIN-WAIT-1(終止等待1)狀態(tài)。TCP規(guī)定,F(xiàn)IN報文段即使不攜帶數(shù)據(jù),也要消耗一個序號。
2、服務(wù)器收到連接釋放報文,發(fā)出確認(rèn)報文,ACK=1,ack=u+1,并且?guī)献约旱男蛄刑杝eq=v,此時,服務(wù)端就進(jìn)入了CLOSE-WAIT(關(guān)閉等待)狀態(tài)。TCP服務(wù)器通知高層的應(yīng)用進(jìn)程,客戶端向服務(wù)器的方向就釋放了,這時候處于半關(guān)閉狀態(tài),即客戶端已經(jīng)沒有數(shù)據(jù)要發(fā)送了,但是服務(wù)器若發(fā)送數(shù)據(jù),客戶端依然要接受。這個狀態(tài)還要持續(xù)一段時間,也就是整個CLOSE-WAIT狀態(tài)持續(xù)的時間。
3、客戶端收到服務(wù)器的確認(rèn)請求后,此時,客戶端就進(jìn)入FIN-WAIT-2(終止等待2)狀態(tài),等待服務(wù)器發(fā)送連接釋放報文(在這之前還需要接受服務(wù)器發(fā)送的最后的數(shù)據(jù))。
4、服務(wù)器將最后的數(shù)據(jù)發(fā)送完畢后,就向客戶端發(fā)送連接釋放報文,F(xiàn)IN=1,ack=u+1,由于在半關(guān)閉狀態(tài),服務(wù)器很可能又發(fā)送了一些數(shù)據(jù),假定此時的序列號為seq=w,此時,服務(wù)器就進(jìn)入了LAST-ACK(最后確認(rèn))狀態(tài),等待客戶端的確認(rèn)。
5、客戶端收到服務(wù)器的連接釋放報文后,必須發(fā)出確認(rèn),ACK=1,ack=w+1,而自己的序列號是seq=u+1,此時,客戶端就進(jìn)入了TIME-WAIT(時間等待)狀態(tài)。注意此時TCP連接還沒有釋放,必須經(jīng)過2∗ *∗MSL(最長報文段壽命)的時間后,當(dāng)客戶端撤銷相應(yīng)的TCB后,才進(jìn)入CLOSED狀態(tài)。
6、服務(wù)器只要收到了客戶端發(fā)出的確認(rèn),立即進(jìn)入CLOSED狀態(tài)。同樣,撤銷TCB后,就結(jié)束了這次的TCP連接。可以看到,服務(wù)器結(jié)束TCP連接的時間要比客戶端早一些。
第四章常見算法
十種常見排序算法可以分為兩大類:
非線性時間比較類排序:通過比較來決定元素間的相對次序,由于其時間復(fù)雜度不能突破O(nlogn),因此稱為非線性時間比較類排序。
線性時間非比較類排序:不通過比較來決定元素間的相對次序,它可以突破基于比較排序的時間下界,以線性時間運行,因此稱為線性時間非比較類排序。

算法優(yōu)劣評價術(shù)語
穩(wěn)定性:
穩(wěn)定:如果 a 原本在 b 前面,而 a = b,排序之后 a 仍然在 b 的前面;
不穩(wěn)定:如果 a 原本在 b 的前面,而 a = b,排序之后 a 可能會出現(xiàn)在 b 的后面;
排序方式:
內(nèi)排序:所有排序操作都在內(nèi)存中完成,占用常數(shù)內(nèi)存,不占用額外內(nèi)存。
外排序:由于數(shù)據(jù)太大,因此把數(shù)據(jù)放在磁盤中,而排序通過磁盤和內(nèi)存的數(shù)據(jù)傳輸才能進(jìn)行,占用額外內(nèi)存。
復(fù)雜度:
時間復(fù)雜度: 一個算法執(zhí)行所耗費的時間。
空間復(fù)雜度: 運行完一個程序所需內(nèi)存的大小。


至于各種算法的原理以及代碼實現(xiàn),由于太多并且比較復(fù)雜,不在本文列出。但推薦兩本入門的書:《啊哈!算法》、《大話數(shù)據(jù)結(jié)構(gòu)》。電子版我會發(fā)在交流群里。
排序算法很多,嵌入式要求的不會太多,你會冒泡排序、快速排序、插入排序就可以解決很多問題。難的比如動態(tài)規(guī)劃問題,圖的路徑問題,嵌入式考的比較少,純軟才會考這些。(大公司和獨角獸公司考的會相對難一些)
第五章Linux操作系統(tǒng)題目
1、 Linux內(nèi)核的組成部分
Linux內(nèi)核主要由五個子系統(tǒng)組成:進(jìn)程調(diào)度,內(nèi)存管理,虛擬文件系統(tǒng),網(wǎng)絡(luò)接口,進(jìn)程間通信。

2、Linux系統(tǒng)的組成部分
Linux系統(tǒng)一般有4個主要部分:
內(nèi)核、shell、文件系統(tǒng)和應(yīng)用程序。

3、用戶空間與內(nèi)核通信方式有哪些?
1)系統(tǒng)調(diào)用。用戶空間進(jìn)程通過系統(tǒng)調(diào)用進(jìn)入內(nèi)核空間,訪問指定的內(nèi)核空間數(shù)據(jù);
2)驅(qū)動程序。用戶空間進(jìn)程可以使用封裝后的系統(tǒng)調(diào)用接口訪問驅(qū)動設(shè)備節(jié)點,以和運行在內(nèi)核空間的驅(qū)動程序通信;
3)共享內(nèi)存mmap。在代碼中調(diào)用接口,實現(xiàn)內(nèi)核空間與用戶空間的地址映射,在實時性要求很高的項目中為首選,省去拷貝數(shù)據(jù)的時間等資源,但缺點是不好控制;
4)copy_to_user()、copy_from_user(),是在驅(qū)動程序中調(diào)用接口,實現(xiàn)用戶空間與內(nèi)核空間的數(shù)據(jù)拷貝操作,應(yīng)用于實時性要求不高的項目中。
以及:
- procfs(/proc)
- sysctl (/proc/sys)
- sysfs(/sys)
- netlink 套接口
4、系統(tǒng)調(diào)用與普通函數(shù)調(diào)用的區(qū)別
系統(tǒng)調(diào)用:
1.使用INT和IRET指令,內(nèi)核和應(yīng)用程序使用的是不同的堆棧,因此存在堆棧的切換,從用戶態(tài)切換到內(nèi)核態(tài),從而可以使用特權(quán)指令操控設(shè)備
2.依賴于內(nèi)核,不保證移植性
3.在用戶空間和內(nèi)核上下文環(huán)境間切換,開銷較大
4.是操作系統(tǒng)的一個入口點
普通函數(shù)調(diào)用:
1.使用CALL和RET指令,調(diào)用時沒有堆棧切換
2.平臺移植性好
3.屬于過程調(diào)用,調(diào)用開銷較小
4.一個普通功能函數(shù)的調(diào)用
5、內(nèi)核態(tài),用戶態(tài)的區(qū)別
內(nèi)核態(tài),操作系統(tǒng)在內(nèi)核態(tài)運行——運行操作系統(tǒng)程序
用戶態(tài),應(yīng)用程序只能在用戶態(tài)運行——運行用戶程序
當(dāng)一個進(jìn)程在執(zhí)行用戶自己的代碼時處于用戶運行態(tài)(用戶態(tài)),此時特權(quán)級最低,為3級,是普通的用戶進(jìn)程運行的特權(quán)級,大部分用戶直接面對的程序都是運行在用戶態(tài)。Ring3狀態(tài)不能訪問Ring0的地址空間,包括代碼和數(shù)據(jù);當(dāng)一個進(jìn)程因為系統(tǒng)調(diào)用陷入內(nèi)核代碼中執(zhí)行時處于內(nèi)核運行態(tài)(內(nèi)核態(tài)),此時特權(quán)級最高,為0級。執(zhí)行的內(nèi)核代碼會使用當(dāng)前進(jìn)程的內(nèi)核棧,每個進(jìn)程都有自己的內(nèi)核棧。
6、 bootloader、內(nèi)核 、根文件的關(guān)系
啟動順序:bootloader->linux kernel->rootfile->app
Bootloader全名為啟動引導(dǎo)程序,是第一段代碼,它主要用來初始化處理器及外設(shè),然后調(diào)用Linux內(nèi)核。Linux內(nèi)核在完成系統(tǒng)的初始化之后需要掛載某個文件系統(tǒng)作為根文件系統(tǒng)(RootFilesystem),然后加載必要的內(nèi)核模塊,啟動應(yīng)用程序。(一個嵌入式Linux系統(tǒng)從軟件角度看可以分為四個部分:引導(dǎo)加載程序(Bootloader),Linux內(nèi)核,文件系統(tǒng),應(yīng)用程序。)
7 、Bootloader啟動的兩個階段:
Stage1:匯編語言
1)基本的硬件初始化(關(guān)閉看門狗和中斷,MMU(帶操作系統(tǒng)),CACHE。配置系統(tǒng)工作時鐘)
2)為加載stage2準(zhǔn)備RAM空間
3)拷貝內(nèi)核映像和文件系統(tǒng)映像到RAM中
4)設(shè)置堆棧指針sp
5)跳到stage2的入口點
Stage2:c語言
1)初始化本階段要使用到的硬件設(shè)備(led uart等)
2)檢測系統(tǒng)的內(nèi)存映射
3)加載內(nèi)核映像和文件系統(tǒng)映像
4)設(shè)置內(nèi)核的啟動參數(shù)
嵌入式系統(tǒng)中廣泛采用的非易失性存儲器通常是Flash,而Bootloader就位于該存儲器的最前端,所以系統(tǒng)上電或復(fù)位后執(zhí)行的第一段程序便是Bootloader。
8、 linux下檢查內(nèi)存狀態(tài)的命令
- 1)查看進(jìn)程:top
- 2)查看內(nèi)存:free
- 3)cat /proc/meminfo
- 4)vmstat
假如一個公司服務(wù)器有很多用戶,你使用top命令,可以看到哪個同事在使用什么命令,做什么事情,占用了多少CPU。
9 、一個程序從開始運行到結(jié)束的完整過程(四個過程)
預(yù)處理(Pre-Processing)、編譯(Compiling)、匯編(Assembling)、鏈接(Linking)
10、什么是堆,棧,內(nèi)存泄漏和內(nèi)存溢出?
棧由系統(tǒng)操作,程序員不可以操作。
所以內(nèi)存泄漏是指堆內(nèi)存的泄漏。堆內(nèi)存是指程序從堆中分配的,大小任意的(內(nèi)存塊的大小可以在程序運行期決定),使用完后必須顯式釋放的內(nèi)存。應(yīng)用程序一般使用malloc,new等函數(shù)從堆中分配到一塊內(nèi)存,使用完后,程序必須負(fù)責(zé)相應(yīng)的調(diào)用free或delete釋放該內(nèi)存塊,否則,這塊內(nèi)存就不能被再次使用。
內(nèi)存溢出:你要求分配的內(nèi)存超出了系統(tǒng)能給你的,系統(tǒng)不能滿足需求,于是產(chǎn)生溢出。
內(nèi)存越界:向系統(tǒng)申請了一塊內(nèi)存,而在使用內(nèi)存時,超出了申請的范圍(常見的有使用特定大小數(shù)組時發(fā)生內(nèi)存越界)
內(nèi)存溢出問題是 C 語言或者 C++ 語言所固有的缺陷,它們既不檢查數(shù)組邊界,又不檢查類型可靠性(type-safety)。眾所周知,用 C/C++ 語言開發(fā)的程序由于目標(biāo)代碼非常接近機器內(nèi)核,因而能夠直接訪問內(nèi)存和寄存器,這種特性大大提升了 C/C++ 語言代碼的性能。只要合理編碼,C/C++ 應(yīng)用程序在執(zhí)行效率上必然優(yōu)于其它高級語言。然而,C/C++ 語言導(dǎo)致內(nèi)存溢出問題的可能性也要大許多。
11、死鎖的原因、條件
產(chǎn)生死鎖的原因主要是:
(1) 因為系統(tǒng)資源不足。
(2) 進(jìn)程運行推進(jìn)的順序不合適。
(3) 資源分配不當(dāng)?shù)取?/p>
如果系統(tǒng)資源充足,進(jìn)程的資源請求都能夠得到滿足,死鎖出現(xiàn)的可能性就很低,否則就會因爭奪有限的資源而陷入死鎖。其次,進(jìn)程運行推進(jìn)順序與速度不同,也可能產(chǎn)生死鎖
這四個條件是死鎖的必要條件,只要系統(tǒng)發(fā)生死鎖,這些條件必然成立,而只要上述條件之一不滿足,就不會發(fā)生死鎖。
(1) 互斥條件:一個資源每次只能被一個進(jìn)程使用。
(2) 請求與保持條件:一個進(jìn)程因請求資源而阻塞時,對已獲得的資源保持不放。
(3) 不剝奪條件:進(jìn)程已獲得的資源,在末使用完之前,不能強行剝奪。
(4) 循環(huán)等待條件:若干進(jìn)程之間形成一種頭尾相接的循環(huán)等待資源關(guān)系。
12、硬鏈接與軟鏈接
鏈接操作實際上是給系統(tǒng)中已有的某個文件指定另外一個可用于訪問它的名稱。對于這個新的文件名,我們可以為之指定不同的訪問權(quán)限,以控制對信息的共享和安全性的問題。如果鏈接指向目錄,用戶就可以利用該鏈接直接進(jìn)入被鏈接的目錄而不用打一大堆的路徑名。而且,即使我們刪除這個鏈接,也不會破壞原來的目錄。
1>硬鏈接
硬鏈接只能引用同一文件系統(tǒng)中的文件。它引用的是文件在文件系統(tǒng)中的物理索引(也稱為inode)。當(dāng)您移動或刪除原始文件時,硬鏈接不會被破壞,因為它所引用的是文件的物理數(shù)據(jù)而不是文件在文件結(jié)構(gòu)中的位置。硬鏈接的文件不需要用戶有訪問原始文件的權(quán)限,也不會顯示原始文件的位置,這樣有助于文件的安全。如果您刪除的文件有相應(yīng)的硬鏈接,那么這個文件依然會保留,直到所有對它的引用都被刪除。
2>軟鏈接(符號鏈接)
軟連接,其實就是新建立一個文件,這個文件就是專門用來指向別的文件的(那就和windows 下的快捷方式的那個文件有很接近的意味)。軟連接產(chǎn)生的是一個新的文件,但這個文件的作用就是專門指向某個文件的,刪了這個軟連接文件,那就等于不需要這個連接,和原來的存在的實體原文件沒有任何關(guān)系,但刪除原來的文件,則相應(yīng)的軟連接不可用。
13、計算機中,32bit與64bit有什么區(qū)別
64bit計算主要有兩大優(yōu)點:可以進(jìn)行更大范圍的整數(shù)運算;可以支持更大的內(nèi)存。
64位操作系統(tǒng)下的虛擬內(nèi)存空間大小:地址空間大小不是2^32,也不是2^64,而一般是2^48。因為并不需要2^64那么大的尋址空間,過大的空間只會造成資源的浪費。所以64位Linux一般使用48位表示虛擬空間地址,40位標(biāo)識物理地址。
14、中斷和異常的區(qū)別
內(nèi)中斷:同步中斷(異常)是由cpu內(nèi)部的電信號產(chǎn)生的中斷,其特點為當(dāng)前執(zhí)行的指令結(jié)束后才轉(zhuǎn)而產(chǎn)生中斷,由于有cpu主動產(chǎn)生,其執(zhí)行點必然是可控的。
外中斷:異步中斷是由cpu的外設(shè)產(chǎn)生的電信號引起的中斷,其發(fā)生的時間點不可預(yù)期。
15、中斷怎么發(fā)生,中斷處理流程
請求中斷→響應(yīng)中斷→關(guān)閉中斷→保留斷點→中斷源識別→保護(hù)現(xiàn)場→中斷服務(wù)子程序→恢復(fù)現(xiàn)場→中斷返回。

16、 Linux 操作系統(tǒng)掛起、休眠、關(guān)機相關(guān)命令
關(guān)機命令有halt, init 0, poweroff ,shutdown -h 時間,其中shutdown是最安全的
重啟命令有reboot,init 6,,shutdow -r時間
在linux命令中reboot是重新啟動,shutdown -r now是立即停止然后重新啟動
具體可用參數(shù)可以百度。
17、說一個linux下編譯優(yōu)化選項:
加:-o
18、在有數(shù)據(jù)cache情況下,DMA數(shù)據(jù)鏈路為:
外設(shè)-DMA-DDR-cache-CPU
19、linux命令
1、改變文件屬性的命令:chmod (chmod 777 /etc/squid 運行命令后,squid文件夾(目錄)的權(quán)限就被修改為777(可讀可寫可執(zhí)行))
2、查找文件中匹配字符串的命令:grep
3、查找當(dāng)前目錄:pwd
4、刪除目錄:rm -rf 目錄名
5、刪除文件:rm 文件名
6、創(chuàng)建目錄(文件夾):mkdir
7、創(chuàng)建文件:touch
8、vi和vim 文件名也可以創(chuàng)建
9、解壓:tar -xzvf 壓縮包
打包:tar -cvzf 目錄(文件夾)
10、查看進(jìn)程對應(yīng)的端口號
- 1、先查看進(jìn)程pid
- ps -ef | grep 進(jìn)程名
- 2、通過pid查看占用端口
- netstat -nap | grep 進(jìn)程pid
20、硬實時系統(tǒng)和軟實時系統(tǒng)
軟實時系統(tǒng):
Windows、Linux系統(tǒng)通常為軟實時,當(dāng)然有補丁可以將內(nèi)核做成硬實時的系統(tǒng),不過商用沒有這么做的。
硬實時系統(tǒng):
對時間要求很高,限定時間內(nèi)不管做沒做完必須返回。
VxWorks,uCOS,F(xiàn)reeRTOS,WinCE,RT-thread等實時系統(tǒng);
21、MMU基礎(chǔ)
現(xiàn)代操作系統(tǒng)普遍采用虛擬內(nèi)存管理(Virtual Memory Management) 機制,這需要MMU( Memory Management Unit,內(nèi)存管理單元) 的支持。有些嵌入式處理器沒有MMU,則不能運行依賴于虛擬內(nèi)存管理的操作系統(tǒng)。
也就是說:操作系統(tǒng)可以分成兩類,用MMU的、不用MMU的。
用MMU的是:Windows、MacOS、Linux、Android;不用MMU的是:FreeRTOS、VxWorks、UCOS……
與此相對應(yīng)的:CPU也可以分成兩類,帶MMU的、不帶MMU的。
帶MMU的是:Cortex-A系列、ARM9、ARM11系列;
不帶MMU的是:Cortex-M系列……(STM32是M系列,沒有MMU,不能運行Linux,只能運行一些UCOS、FreeRTOS等等)。
MMU就是負(fù)責(zé)虛擬地址(virtual address)轉(zhuǎn)化成物理地址(physical address),轉(zhuǎn)換過程比較復(fù)雜,可以自行百度。
第六章 單片機常見面試題
1、ROM與RAM
這一點我另一篇文章講解過,這里放鏈接:
ROM與RAM的區(qū)別
2、 IO口工作方式(學(xué)過STM32的人應(yīng)該很熟悉)
上拉輸入、下拉輸入、推挽輸出、開漏輸出。
3、請說明總線接口USRT、I2C、USB的異同點
(串/并、速度、全/半雙工、總線拓?fù)涞?

4、IIC協(xié)議時序圖
必須會畫出來,我面試被問到過,讓我畫,我畫了個大概。
IIC協(xié)議有兩根線,一根SCL時鐘線,一根SDA數(shù)據(jù)線,如圖可以看到開始信號和結(jié)束信號的電平狀態(tài)。開始后,因為IIC總線可以掛在很多設(shè)備(不超過8個),所以先發(fā)送一個設(shè)備地址,選中這個設(shè)備,設(shè)備地址最后一位代表了是寫還是讀。選中設(shè)備后,再發(fā)送寄存器地址,代表選中某個寄存器,再開始傳輸數(shù)據(jù)。
八位設(shè)備地址=7位從機地址+讀/寫地址,
再給地址添加一個方向位位用來表示接下來數(shù)據(jù)傳輸?shù)姆较颍?/p>
0表示主設(shè)備向從設(shè)備(write)寫數(shù)據(jù),
1表示主設(shè)備向從設(shè)備(read)讀數(shù)據(jù)

開始信號:SCL 為高電平時,SDA 由高電平向低電平跳變,開始傳送數(shù)據(jù)。
結(jié)束信號:SCL 為高電平時,SDA 由低電平向高電平跳變,結(jié)束傳送數(shù)據(jù)。
應(yīng)答信號:接收數(shù)據(jù)的 IC 在接收到 8bit 數(shù)據(jù)后,向發(fā)送數(shù)據(jù)的 IC 發(fā)出特定的低電平脈沖,表示已收到數(shù)據(jù)。CPU 向受控單元發(fā)出一個信號后,等待受控單元發(fā)出一個應(yīng)答信號,CPU 接收到應(yīng)答信號后,根據(jù)實際情況作出是否繼續(xù)傳遞信號的判斷。若未收到應(yīng)答信號,由判斷為受控單元出現(xiàn)故障。
IIC信號在數(shù)據(jù)傳輸過程中,當(dāng)SCL=1高電平時,數(shù)據(jù)線SDA必須保持穩(wěn)定狀態(tài),不允許有電平跳變,只有在時鐘線上的信號為低電平期間,數(shù)據(jù)線上的高電平或低電平狀態(tài)才允許變化。SCL=1時 數(shù)據(jù)線SDA的任何電平變換會看做是總線的起始信號或者停止信號。
IIC我也有一篇文章有講解,請看鏈接:
IIC總線最多可以掛多少個設(shè)備
5、單片機的SP指針始終指向
棧頂
6、IIC總線在傳送數(shù)據(jù)過程中共有三種類型信號:
它們分別是:開始信號、結(jié)束信號和應(yīng)答信號。
7、FIQ中斷向量入口地址:
FIQ和IRQ是兩種不同類型的中斷,ARM為了支持這兩種不同的中斷,提供了對應(yīng)的叫做FIQ和IRQ處理器模式(ARM有7種處理模式)。
FIQ的中斷向量地址在0x0000001C,而IRQ的在0x00000018。
8、SPI四種模式,簡述其中一種模式,畫出時序圖
在芯片資料上極性和相位一般表示為CPOL(Clock POLarity)和CPHA(Clock PHAse), 極性和相位組合成4種工作模式。

spi四種模式SPI的相位(CPHA)和極性(CPOL)分別可以為0或1,對應(yīng)的4種組合構(gòu)成了SPI的4種模式(mode)
Mode 0 CPOL=0, CPHA=0
Mode 1 CPOL=0, CPHA=1
Mode 2 CPOL=1, CPHA=0
Mode 3 CPOL=1, CPHA=1
時鐘極性CPOL: 即SPI空閑時,時鐘信號SCLK的電平(1:空閑時高電平; 0:空閑時低電平) 時鐘相位CPHA: 即SPI在SCLK第幾個邊沿開始采樣(0:第一個邊沿開始; 1:第二個邊沿開始)
sd卡的spi常用的是mode 0 和mode 3,這兩種模式的相同的地方是都在時鐘上升沿采樣傳輸數(shù)據(jù),區(qū)別這兩種方式的簡單方法就是看空閑時,時鐘的電平狀態(tài),低電平為mode 0 ,高電平為mode 3。
具體的通信過程請自行百度,2021年秋招大疆筆試題考了這道題。
第七章 雜項面試題
1、講一講馮諾依曼和哈佛體系的區(qū)別
哈佛結(jié)構(gòu)是一種將程序指令存儲和數(shù)據(jù)存儲分開的存儲器結(jié)構(gòu)。目前使用哈佛結(jié)構(gòu)的中央處理器和微控制器有很多,ARM9、ARM10和ARM11,51單片機屬于哈佛結(jié)構(gòu)。
馮·諾伊曼結(jié)構(gòu)也稱普林斯頓結(jié)構(gòu),是一種將程序指令存儲器和數(shù)據(jù)存儲器合并在一起的存儲器結(jié)構(gòu)。
2、面向?qū)ο缶幊痰娜筇匦?/strong>
以及重載的意思。重載,是指允許存在多個同名函數(shù),而這些函數(shù)的參數(shù)表不同(或許參數(shù)個數(shù)不同,或許參數(shù)類型不同,或許兩者都不同)。
3、http默認(rèn)端口號
80
4、linux中mysql數(shù)據(jù)庫默認(rèn)的端口是
3306
5、編程習(xí)慣小知識點
C語言編程中,單片機平臺,一般有.c和.h文件,如果一個人在.h文件中定義了一個變量,會有什么后果。(討論編程習(xí)慣的問題,我一般是只在.h文件中聲明函數(shù),不會做變量定義;另外,編程中每一個模塊都會有對應(yīng)的.c和.h文件,最終的總程序自己定義一個comm.c和comm.h去調(diào)用各個模塊,這樣的習(xí)慣我覺得還行)
if語句中如果是或運算( | ),第一個條件滿足時,第二個條件還會判斷嗎。或運算的話,當(dāng)然不會,因為 0|1=1,中斷了