當(dāng)前位置:首頁(yè) > 嵌入式培訓(xùn) > 嵌入式學(xué)習(xí) > 入門(mén)指導(dǎo) > 嵌入式題庫(kù)最全的,去公司面試都會(huì)出現(xiàn)
現(xiàn)在嵌入式發(fā)展這么快,很多人開(kāi)始踏上嵌入式學(xué)習(xí)之路,據(jù)市場(chǎng)統(tǒng)計(jì),一般畢業(yè)或者找工作的一些人,在面試公司的時(shí)候,都會(huì)在這個(gè)地方卡殼,那就是面試題,很多人都是面試的很好,但是在做面試題的時(shí)候,手下的功夫不夠深,最后被面試題而刷了下來(lái),使得找工作變成了難題,空有一身的才華了,而且這也是對(duì)一些嵌入式面試的一些空難戶(hù)而總結(jié),可以學(xué)學(xué)哦,去公司面試一般都是會(huì)有的。
(1)char * constp char const * p const char *p 上述三個(gè)有什么區(qū)別?
答案:
char * const p; //常量指針,p的值不可以修改
char const * p;//指向常量的指針,指向的常量值不可以改 const char *p; //和char const *p
char * const p是一個(gè)char型指針,指針是常量,不允許修改,即類(lèi)似p=q的語(yǔ)句是錯(cuò)誤的;
char const * p和const char * p是同一種char型指針,指針指向的字符被看作是常量,不允許修改,即類(lèi)似*p = q的語(yǔ)句是錯(cuò)誤的。
(2)char str1[] = "abc"; charstr2[] = "abc"; const char str3[] = "abc"; const charstr4[] = "abc"; const char *str5 = "abc"; const char *str6= "abc"; char *str7 = "abc"; char *str8 = "abc";cout < < ( str1 == str2 ) < < endl; cout < < ( str3 == str4 )< < endl; cout < < ( str5 == str6 ) < < endl; cout < <( str7 == str8 ) < < endl;
結(jié)果是:0 0 1 1str1,str2,str3,str4是數(shù)組變量,它們有各自的內(nèi)存空間;而str5,str6,str7,str8是指針,它們指向相同的常量區(qū)域。
(3)什么是預(yù)編譯,何時(shí)需要預(yù)編譯:
答案:
1、總是使用不經(jīng)常改動(dòng)的大型代碼體。
2、程序由多個(gè)模塊組成,所有模塊都使用一組標(biāo)準(zhǔn)的包含文件和相同的編譯選項(xiàng)。在這種情況下,可以將所有包含文件預(yù)編譯為一個(gè)預(yù)編譯頭。
預(yù)編譯指令指示了在程序正式編譯前就由編譯器進(jìn)行的操作,可以放在程序中的任何位置。
(4)以下代碼中的兩個(gè)sizeof用法有問(wèn)題嗎?
[C易] void UpperCase( char str[] ) // 將 str 中的小寫(xiě)字母轉(zhuǎn)換成大寫(xiě)字母{ for( size_t i=0; i
(5)嵌入式系統(tǒng)中經(jīng)常要用到無(wú)限循環(huán),你怎么樣用C編寫(xiě)死循環(huán)呢?
這個(gè)問(wèn)題用幾個(gè)解決方案。我首選的方案是:
while(1)
{
}
一些程序員更喜歡如下方案:
for(;;)
{
}
這個(gè)實(shí)現(xiàn)方式讓我為難,因?yàn)檫@個(gè)語(yǔ)法沒(méi)有確切表達(dá)到底怎么回事。如果一個(gè)應(yīng)試者給出
這個(gè)作為方案,我將用這個(gè)作為一個(gè)機(jī)會(huì)去探究他們這樣做的
基本原理。如果他們的基本答案是:“我被教著這樣做,但從沒(méi)有想到過(guò)為什么。”這會(huì)
給我留下一個(gè)壞印象。
第三個(gè)方案是用 goto
Loop:
...
goto Loop;
應(yīng)試者如給出上面的方案,這說(shuō)明或者他是一個(gè)匯編語(yǔ)言程序員(這也許是好事)或者他
是一個(gè)想進(jìn)入新領(lǐng)域的BASIC/FORTRAN程序員。
Const
(6)關(guān)鍵字const是什么含意?
我只要一聽(tīng)到被面試者說(shuō):“const意味著常數(shù)”,我就知道我正在和一個(gè)業(yè)余者打交道。
去年Dan Saks已經(jīng)在他的文章里完全概括了const的所有用法,因此ESP(譯者:Embedded
Systems Programming)的每一位讀者應(yīng)該非常熟悉const能做什么和不能做什么.如果你從
沒(méi)有讀到那篇文章,只要能說(shuō)出const意味著“只讀”就可以了。盡管這個(gè)答案不是完全的
答案,但我接受它作為一個(gè)正確的答案。(如果你想知道更詳細(xì)的答案,仔細(xì)讀一下Saks
的文章吧。)如果應(yīng)試者能正確回答這個(gè)問(wèn)題,我將問(wèn)他一個(gè)附加的問(wèn)題:下面的聲明都
是什么意思?
const int a;
int const a;
const int *a;
int * const a;
int const * a const;
前兩個(gè)的作用是一樣,a是一個(gè)常整型數(shù)。第三個(gè)意味著a是一個(gè)指向常整型數(shù)的指針(也
就是,整型數(shù)是不可修改的,但指針可以)。第四個(gè)意思a是一個(gè)指向整型數(shù)的常指針(也
就是說(shuō),指針指向的整型數(shù)是可以修改的,但指針是不可修改的)。最后一個(gè)意味著a是一
個(gè)指向常整型數(shù)的常指針(也就是說(shuō),指針指向的整型數(shù)是不可修改的,同時(shí)指針也是不
可修改的)。如果應(yīng)試者能正確回答這些問(wèn)題,那么他就給我留下了一個(gè)好印象。順帶提
一句,也許你可能會(huì)問(wèn),即使不用關(guān)鍵字const,也還是能很容易寫(xiě)出功能正確的程序,那
么我為什么還要如此看重關(guān)鍵字const呢?我也如下的幾下理由:
1). 關(guān)鍵字const的作用是為給讀你代碼的人傳達(dá)非常有用的信息,實(shí)際上,聲明一個(gè)參數(shù)
為常量是為了告訴了用戶(hù)這個(gè)參數(shù)的應(yīng)用目的。如果你曾花很多時(shí)間清理其它人留下的垃
圾,你就會(huì)很快學(xué)會(huì)感謝這點(diǎn)多余的信息。(當(dāng)然,懂得用const的程序員很少會(huì)留下的垃
圾讓別人來(lái)清理的。)
2). 通過(guò)給優(yōu)化器一些附加的信息,使用關(guān)鍵字const也許能產(chǎn)生更緊湊的代碼。
3). 合理地使用關(guān)鍵字const可以使編譯器很自然地保護(hù)那些不希望被改變的參數(shù),防止其
被無(wú)意的代碼修改。簡(jiǎn)而言之,這樣可以減少bug的出現(xiàn)。
Volatile
(7)關(guān)鍵字volatile有什么含意 并給出三個(gè)不同的例子。
一個(gè)定義為volatile的變量是說(shuō)這變量可能會(huì)被意想不到地改變,這樣,編譯器就不會(huì)去
假設(shè)這個(gè)變量的值了。精確地說(shuō)就是,優(yōu)化器在用到這個(gè)變量時(shí)必須每次都小心地重新讀
取這個(gè)變量的值,而不是使用保存在寄存器里的備份。下面是volatile變量的幾個(gè)例子:
1). 并行設(shè)備的硬件寄存器(如:狀態(tài)寄存器)
2). 一個(gè)中斷服務(wù)子程序中會(huì)訪(fǎng)問(wèn)到的非自動(dòng)變量(Non-automatic variables)
3). 多線(xiàn)程應(yīng)用中被幾個(gè)任務(wù)共享的變量
回答不出這個(gè)問(wèn)題的人是不會(huì)被雇傭的。我認(rèn)為這是區(qū)分C程序員和嵌入式系統(tǒng)程序員的最
基本的問(wèn)題。嵌入式系統(tǒng)程序員經(jīng)常同硬件、中斷、RTOS等等打交道,所用這些都要求vo
latile變量。不懂得volatile內(nèi)容將會(huì)帶來(lái)災(zāi)難。
假設(shè)被面試者正確地回答了這是問(wèn)題(嗯,懷疑這否會(huì)是這樣),我將稍微深究一下,看
一下這家伙是不是直正懂得volatile完全的重要性。
1). 一個(gè)參數(shù)既可以是const還可以是volatile嗎?解釋為什么。
2). 一個(gè)指針可以是volatile 嗎?解釋為什么。
3). 下面的函數(shù)有什么錯(cuò)誤:
int square(volatile int *ptr)
{
return *ptr * *ptr;
}
下面是答案:
1). 是的。一個(gè)例子是只讀的狀態(tài)寄存器。它是volatile因?yàn)樗赡鼙灰庀氩坏降馗淖儭?/p>
它是const因?yàn)槌绦虿粦?yīng)該試圖去修改它。
2). 是的。盡管這并不很常見(jiàn)。一個(gè)例子是當(dāng)一個(gè)中服務(wù)子程序修該一個(gè)指向一個(gè)buffer
的指針時(shí)。
3). 這段代碼的有個(gè)惡作劇。這段代碼的目的是用來(lái)返指針*ptr指向值的平方,但是,由
于*ptr指向一個(gè)volatile型參數(shù),編譯器將產(chǎn)生類(lèi)似下面的代碼:
int square(volatile int *ptr)
{
int a,b;
a = *ptr;
b = *ptr;
return a * b;
}
由于*ptr的值可能被意想不到地該變,因此a和b可能是不同的。結(jié)果,這段代碼可能返不
是你所期望的平方值!正確的代碼如下:
long square(volatile int *ptr)
{
int a;
a = *ptr;
return a * a;
}
位操作(Bit manipulation)
(8)嵌入式系統(tǒng)總是要用戶(hù)對(duì)變量或寄存器進(jìn)行位操作。給定一個(gè)整型變量a,寫(xiě)兩段代碼
,第一個(gè)設(shè)置a的bit 3,第二個(gè)清除a 的bit 3。在以上兩個(gè)操作中,要保持其它位不變。
對(duì)這個(gè)問(wèn)題有三種基本的反應(yīng)
1). 不知道如何下手。該被面者從沒(méi)做過(guò)任何嵌入式系統(tǒng)的工作。
2). 用bit fields。Bit fields是被扔到C語(yǔ)言死角的東西,它保證你的代碼在不同編譯器
之間是不可移植的,同時(shí)也保證了的你的代碼是不可重用的。我最近不幸看到Infineon為
其較復(fù)雜的通信芯片寫(xiě)的驅(qū)動(dòng)程序,它用到了bit fields因此完全對(duì)我無(wú)用,因?yàn)槲业木?/p>
譯器用其它的方式來(lái)實(shí)現(xiàn)bit fields的。從道德講:永遠(yuǎn)不要讓一個(gè)非嵌入式的家伙粘實(shí)
際硬件的邊。
3). 用 #defines 和 bit masks 操作。這是一個(gè)有極高可移植性的方法,是應(yīng)該被用到的
方法。最佳的解決方案如下:
#define BIT3 (0x1 < <3)
static int a;
void set_bit3(void)
{
a |= BIT3;
}
void clear_bit3(void)
{
a &= ~BIT3;
}
一些人喜歡為設(shè)置和清除值而定義一個(gè)掩碼同時(shí)定義一些說(shuō)明常數(shù),這也是可以接受的。
我希望看到幾個(gè)要點(diǎn):說(shuō)明常數(shù)、|=和&=~操作。
數(shù)據(jù)聲明(Data declarations)
(9)用變量a給出下面的定義
a) 一個(gè)整型數(shù)(An integer)
b) 一個(gè)指向整型數(shù)的指針(A pointer to an integer)
c) 一個(gè)指向指針的的指針,它指向的指針是指向一個(gè)整型數(shù)(A pointer to a pointer
to an integer)
d) 一個(gè)有10個(gè)整型數(shù)的數(shù)組(An array of 10 integers)
e) 一個(gè)有10個(gè)指針的數(shù)組,該指針是指向一個(gè)整型數(shù)的(An array of 10 pointers to
integers)
f) 一個(gè)指向有10個(gè)整型數(shù)數(shù)組的指針(A pointer to an array of 10 integers)
g) 一個(gè)指向函數(shù)的指針,該函數(shù)有一個(gè)整型參數(shù)并返回一個(gè)整型數(shù)(A pointer to a fu
nction that takes an integer as an argument and returns an integer)
h) 一個(gè)有10個(gè)指針的數(shù)組,該指針指向一個(gè)函數(shù),該函數(shù)有一個(gè)整型參數(shù)并返回一個(gè)整型
數(shù)( An array of ten pointers to functions that take an integer argument and r
eturn an integer )
答案是:
a) int a; // An integer
b) int *a; // A pointer to an integer
c) int **a; // A pointer to a pointer to an integer
d) int a[10]; // An array of 10 integers
e) int *a[10]; // An array of 10 pointers to integers
f) int (*a)[10]; // A pointer to an array of 10 integers
g) int (*a)(int); // A pointer to a function a that takes an integer argument
and returns an integer
h) int (*a[10])(int); // An array of 10 pointers to functions that take an int
eger argument and return an integer
人們經(jīng)常聲稱(chēng)這里有幾個(gè)問(wèn)題是那種要翻一下書(shū)才能回答的問(wèn)題,我同意這種說(shuō)法。當(dāng)我
寫(xiě)這篇文章時(shí),為了確定語(yǔ)法的正確性,我的確查了一下書(shū)。
但是當(dāng)我被面試的時(shí)候,我期望被問(wèn)到這個(gè)問(wèn)題(或者相近的問(wèn)題)。因?yàn)樵诒幻嬖嚨倪@
段時(shí)間里,我確定我知道這個(gè)問(wèn)題的答案。應(yīng)試者如果不知道
所有的答案(或至少大部分答案),那么也就沒(méi)有為這次面試做準(zhǔn)備,如果該面試者沒(méi)有
為這次面試做準(zhǔn)備,那么他又能為什么出準(zhǔn)備呢?
Static
(10) 關(guān)鍵字static的作用是什么?
這個(gè)簡(jiǎn)單的問(wèn)題很少有人能回答完全。在C語(yǔ)言中,關(guān)鍵字static有三個(gè)明顯的作用:
1). 在函數(shù)體,一個(gè)被聲明為靜態(tài)的變量在這一函數(shù)被調(diào)用過(guò)程中維持其值不變。
2). 在模塊內(nèi)(但在函數(shù)體外),一個(gè)被聲明為靜態(tài)的變量可以被模塊內(nèi)所用函數(shù)訪(fǎng)問(wèn),
但不能被模塊外其它函數(shù)訪(fǎng)問(wèn)。它是一個(gè)本地的全局變量。
3). 在模塊內(nèi),一個(gè)被聲明為靜態(tài)的函數(shù)只可被這一模塊內(nèi)的其它函數(shù)調(diào)用。那就是,這
個(gè)函數(shù)被限制在聲明它的模塊的本地范圍內(nèi)使用。
大多數(shù)應(yīng)試者能正確回答第一部分,一部分能正確回答第二部分,同是很少的人能懂得第
三部分。這是一個(gè)應(yīng)試者的嚴(yán)重的缺點(diǎn),因?yàn)樗@然不懂得本地化數(shù)據(jù)和代碼范圍的好處
和重要性。
(11)一個(gè)32位的機(jī)器,該機(jī)器的指針是多少位答案:
指針是多少位只要看地址總線(xiàn)的位數(shù)就行了。80386以后的機(jī)子都是32的數(shù)據(jù)總線(xiàn)。所以指針的位數(shù)就是4個(gè)字節(jié)了。
(12) main()
{
inta[5]={1,2,3,4,5};
int *ptr=(int*)(&a+1);
printf("%d,%d",*(a+1),*(ptr-1));
}
答案:2。5 *(a+1)就是a[1],*(ptr-1)就是a[4],執(zhí)行結(jié)果是2,5 &a+1不是首地址+1,系統(tǒng)會(huì)認(rèn)為加一個(gè)a數(shù)組的偏移,是偏移了一個(gè)數(shù)組的大小(本例是5個(gè)int) int *ptr=(int *)(&a+1); 則ptr實(shí)際是&(a[5]),也就是a+5 原因如下: &a是數(shù)組指針,其類(lèi)型為 int (*)[5]; 而指針加1要根據(jù)指針類(lèi)型加上一定的值,不同類(lèi)型的指針+1之后增加的大小不同 a是長(zhǎng)度為5的int數(shù)組指針,所以要加5*sizeof(int) 所以ptr實(shí)際是a[5] 但是prt與(&a+1)類(lèi)型是不一樣的(這點(diǎn)很重要) 所以prt-1只會(huì)減去sizeof(int*) a,&a的地址是一樣的,但意思不一樣,a是數(shù)組首地址,也就是a[0]的地址,&a是對(duì)象(數(shù)組)首地址,a+1是數(shù)組下一元素的地址,即a[1],&a+1是下一個(gè)對(duì)象的地址,即a[5].
(13)請(qǐng)問(wèn)以下代碼有什么問(wèn)題:
int main() { chara; char *str=&a; strcpy(str,"hello"); printf(str); return 0; }
答案:沒(méi)有為str分配內(nèi)存空間,將會(huì)發(fā)生異常問(wèn)題出在將一個(gè)字符串復(fù)制進(jìn)一個(gè)字符變量指針?biāo)傅刂。雖然可以正確輸出結(jié)果,但因?yàn)樵浇邕M(jìn)行內(nèi)在讀寫(xiě)而導(dǎo)致程序崩潰。
(14)char* s="AAA"; printf("%s",s); s[0]='B'; printf("%s",s);有什么錯(cuò)?
答案:"AAA"是字符串常量。s是指針,指向這個(gè)字符串常量,所以聲明s的時(shí)候就有問(wèn)題。 cosnt char*s="AAA"; 然后又因?yàn)槭浅A浚詫?duì)是s[0]的賦值操作是不合法的。
(15)寫(xiě)一個(gè)“標(biāo)準(zhǔn)”宏,這個(gè)宏輸入兩個(gè)參數(shù)并返回較小的一個(gè)。
答案:.#defineMin(X, Y) ((X)>(Y)?(Y):(X)) //結(jié)尾沒(méi)有‘;’
(16)嵌入式系統(tǒng)中經(jīng)常要用到無(wú)限循環(huán),你怎么用C編寫(xiě)死循環(huán)。
答案:while(1){}或者for(;;)
(17)關(guān)鍵字static的作用是什么?
答案:定義靜態(tài)變量
(18)關(guān)鍵字const有什么含意?
答案:表示常量不可以修改的變量。
(19)關(guān)鍵字volatile有什么含意?并舉出三個(gè)不同的例子?
答案:提示編譯器對(duì)象的值可能在編譯器未監(jiān)測(cè)到的情況下改變。
(20)int (*s[10])(int) 表示的是什么啊?
答案:int(*s[10])(int) 函數(shù)指針數(shù)組,每個(gè)指針指向一個(gè)int func(int param)的函數(shù)。
(21)有以下表達(dá)式: int a=248; b=4;int const c=21;const int *d=&a; int *conste=&b;int const *f const =&a; 請(qǐng)問(wèn)下列表達(dá)式哪些會(huì)被編譯器禁止?為什么?
答案:*c=32;d=&b;*d=43;e=34;e=&a;f=0x321f; *c 這是個(gè)什么東東,禁止 *d 說(shuō)了是const, 禁止 e = &a 說(shuō)了是const 禁止 const *fconst =&a; 禁止
(22)交換兩個(gè)變量的值,不使用第三個(gè)變量。即a=3,b=5,交換之后a=5,b=3;
答案:有兩種解法, 一種用算術(shù)算法, 一種用^(異或) a = a + b; b = a - b; a = a - b; or a = a^b;// 只能對(duì)int,char.. b = a^b; a = a^b; or a^= b ^= a;
(23)c和c++中的struct有什么不同?
答案:c和c++中struct的主要區(qū)別是c中的struct不可以含有成員函數(shù),而c++中的struct可以。c++中struct和class的主要區(qū)別在于默認(rèn)的存取權(quán)限不同,struct默認(rèn)為public,而class默認(rèn)為private
(24)#include
#include
void getmemory(char *p)
{
p=(char *)malloc(100);
strcpy(p,"helloworld");
}
int main( )
{
char*str=NULL;
getmemory(str);
printf("%s/n",str);
free(str); return 0;
}
答案:程序崩潰,getmemory中的malloc 不能返回動(dòng)態(tài)內(nèi)存, free()對(duì)str操作很危險(xiǎn)
(25)charszstr[10]; strcpy(szstr,"0123456789"); 產(chǎn)生什么結(jié)果?為什么?
答案: 長(zhǎng)度不一樣,會(huì)造成非法的OS
(26)列舉幾種進(jìn)程的同步機(jī)制,并比較其優(yōu)缺點(diǎn)。答案: 原子操作 信號(hào)量機(jī)制 自旋鎖 管程,會(huì)合,分布式系統(tǒng)
(27)進(jìn)程之間通信的途徑
答案:共享存儲(chǔ)系統(tǒng)消息傳遞系統(tǒng)管道:以文件系統(tǒng)為基礎(chǔ)
(28)進(jìn)程死鎖的原因
答案:資源競(jìng)爭(zhēng)及進(jìn)程推進(jìn)順序非法
(29)死鎖的4個(gè)必要條件
答案:互斥、請(qǐng)求保持、不可剝奪、環(huán)路
(30)死鎖的處理
答案:鴕鳥(niǎo)策略、預(yù)防策略、避免策略、檢測(cè)與解除死鎖
(31)操作系統(tǒng)中進(jìn)程調(diào)度策略有哪幾種?
答案:FCFS(先來(lái)先服務(wù)),優(yōu)先級(jí),時(shí)間片輪轉(zhuǎn),多級(jí)反饋
(32)類(lèi)的靜態(tài)成員和非靜態(tài)成員有何區(qū)別?
答案:類(lèi)的靜態(tài)成員每個(gè)類(lèi)只有一個(gè),非靜態(tài)成員每個(gè)對(duì)象一個(gè)
(33)純虛函數(shù)如何定義?使用時(shí)應(yīng)注意什么?
答案:virtualvoid f()=0; 是接口,子類(lèi)必須要實(shí)現(xiàn)
(24)數(shù)組和鏈表的區(qū)別
答案:數(shù)組:數(shù)據(jù)順序存儲(chǔ),固定大小連表:數(shù)據(jù)可以隨機(jī)存儲(chǔ),大小可動(dòng)態(tài)改變
這些都是你在面試中,會(huì)遇到的一些面試問(wèn)題,趕緊好好積累起來(lái),那樣對(duì)你以后的嵌入式學(xué)習(xí)或者嵌入式面試都會(huì)是巨大的財(cái)富,嵌入式題庫(kù)這里沒(méi)有最好,只有更好,好好掌握這些嵌入式題庫(kù),那對(duì)于嵌入式來(lái)說(shuō)面試so easy。
相關(guān)推薦:嵌入式其他綜合面試題