嵌入式軟件工程師測(cè)試題21道與簡(jiǎn)析
1. C語言中,修飾符volatile含義是什么?其應(yīng)用場(chǎng)合有哪些?
答:volatile關(guān)鍵字的作用
volatile提醒編譯器它后面所定義的變量隨時(shí)都有可能改變,因此編譯后的程序每次需要存儲(chǔ)或讀取這個(gè)變量的時(shí)候,都會(huì)直接從變量地址中讀取數(shù)據(jù)。如果沒有volatile關(guān)鍵字,則編譯器可能優(yōu)化讀取和存儲(chǔ),可能暫時(shí)使用寄存器中的值,如果這個(gè)變量由別的程序更新了的話,將出現(xiàn)不一致的現(xiàn)象。下面舉例說明。在DSP開發(fā)中,經(jīng)常需要等待某個(gè)事件的觸發(fā),所以經(jīng)常會(huì)寫出這樣的程序:
short flag;
void test()
{
do1();
while(flag==0);
do2();
}
這段程序等待內(nèi)存變量flag的值變?yōu)?(懷疑此處是0,有點(diǎn)疑問,)之后才運(yùn)行do2()。變量flag的值由別的程序更改,這個(gè)程序可能是某個(gè)硬件中斷服務(wù)程序。例如:如果某個(gè)按鈕按下的話,就會(huì)對(duì)DSP產(chǎn)生中斷,在按鍵中斷程序中修改flag為1,這樣上面的程序就能夠得以繼續(xù)運(yùn)行。但是,編譯器并不知道flag的值會(huì)被別的程序修改,因此在它進(jìn)行優(yōu)化的時(shí)候,可能會(huì)把flag的值先讀入某個(gè)寄存器,然后等待那個(gè)寄存器變?yōu)?。如果不幸進(jìn)行了這樣的優(yōu)化,那么while循環(huán)就變成了死循環(huán),因?yàn)榧拇嫫鞯膬?nèi)容不可能被中斷服務(wù)程序修改。為了讓程序每次都讀取真正flag變量的值,就需要定義為如下形式:
volatile short flag;
需要注意的是,沒有volatile也可能能正常運(yùn)行,但是可能修改了編譯器的優(yōu)化級(jí)別之后就又不能正常運(yùn)行了。因此經(jīng)常會(huì)出現(xiàn)debug版本正常,但是release版本卻不能正常的問題。所以為了安全起見,只要是等待別的程序修改某個(gè)變量的話,就加上volatile關(guān)鍵字。
2. 請(qǐng)問TCP/IP協(xié)議分為哪幾層?FTP協(xié)議在哪一層?
答:
TCP/IP整體構(gòu)架概述
TCP/IP協(xié)議并不完全符合OSI的七層參考模型。傳統(tǒng)的開放式系統(tǒng)互連參考模型,是一種通信協(xié)議的7層抽象的參考模型,其中每一層執(zhí)行某一特定任務(wù)。該模型的目的是使各種硬件在相同的層次上相互通信。這7層是:物理層、數(shù)據(jù)鏈路層、網(wǎng)絡(luò)層、傳輸層、會(huì)話層、表示層和應(yīng)用層。而TCP/IP通訊協(xié)議采用了4層的層級(jí)結(jié)構(gòu),每一層都呼叫它的下一層所提供的網(wǎng)絡(luò)來完成自己的需求。這4層分別為:
應(yīng)用層:應(yīng)用程序間溝通的層,如簡(jiǎn)單電子郵件傳輸(SMTP)、文件傳輸協(xié)議(FTP)、網(wǎng)絡(luò)遠(yuǎn)程訪問協(xié)議(Telnet)等。
傳輸層:在此層中,它提供了節(jié)點(diǎn)間的數(shù)據(jù)傳送服務(wù),如傳輸控制協(xié)議(TCP)、用戶數(shù)據(jù)報(bào)協(xié)議(UDP)等,TCP和UDP給數(shù)據(jù)包加入傳輸數(shù)據(jù)并把它傳輸?shù)较乱粚又?,這一層負(fù)責(zé)傳送數(shù)據(jù),并且確定數(shù)據(jù)已被送達(dá)并接收。
互連網(wǎng)絡(luò)層:負(fù)責(zé)提供基本的數(shù)據(jù)封包傳送功能,讓每一塊數(shù)據(jù)包都能夠到達(dá)目的主機(jī)(但不檢查是否被正確接收),如網(wǎng)際協(xié)議(IP)。
網(wǎng)絡(luò)接口層:對(duì)實(shí)際的網(wǎng)絡(luò)媒體的管理,定義如何使用實(shí)際網(wǎng)絡(luò)(如Ethernet、SerialLine等)來傳送數(shù)據(jù)。
3. 在網(wǎng)絡(luò)應(yīng)用中,函數(shù)htons,htonl,ntohs,ntohl的作用是什么?
答:
htons
htons函數(shù)用來轉(zhuǎn)換u_short來自主機(jī)的TCP / IP網(wǎng)絡(luò)字節(jié)順序(即big-endian )的. u_short htons ( u_short hostshort ) ; 參數(shù)hostshort [ ] 16位元數(shù)的主機(jī)字節(jié)順序. 返回值的htons函數(shù)返回值的TCP /IP網(wǎng)絡(luò)字節(jié)順序. 須知htons函數(shù)有一個(gè)16位號(hào)碼主機(jī)字節(jié)順序并返回一個(gè)16位數(shù)字網(wǎng)絡(luò)字節(jié)命令中使用的TCP /IP網(wǎng)絡(luò).
htonl
將主機(jī)的無符號(hào)長(zhǎng)整形數(shù)轉(zhuǎn)換成網(wǎng)絡(luò)字節(jié)順序。
#include <winsock.h>
u_long PASCAL FAR htonl( u_long hostlong);
hostlong:主機(jī)字節(jié)順序表達(dá)的32位數(shù)。
注釋:
本函數(shù)將一個(gè)32位數(shù)從主機(jī)字節(jié)順序轉(zhuǎn)換成網(wǎng)絡(luò)字節(jié)順序。
返回值:htonl()返回一個(gè)網(wǎng)絡(luò)字節(jié)順序的值。
參見:htons(), ntohl(), ntohs().
ntohs
將一個(gè)無符號(hào)短整形數(shù)從網(wǎng)絡(luò)字節(jié)順序轉(zhuǎn)換為主機(jī)字節(jié)順序。
#include<winsock.h>
u_short PASCAL FAR ntohs(u_short netshort);
netshort:一個(gè)以網(wǎng)絡(luò)字節(jié)順序表達(dá)的16位數(shù)。
注釋:
本函數(shù)將一個(gè)16位數(shù)由網(wǎng)絡(luò)字節(jié)順序轉(zhuǎn)換為主機(jī)字節(jié)順序。
返回值:ntohs()返回一個(gè)以主機(jī)字節(jié)順序表達(dá)的數(shù)。
參見:htonl(), htons(),ntohl().
ntohl
將一個(gè)無符號(hào)長(zhǎng)整形數(shù)從網(wǎng)絡(luò)字節(jié)順序轉(zhuǎn)換為主機(jī)字節(jié)順序。
?。nclude <winsock.h>
u_long PASCAL FAR ntohl(u_long netlong);
netlong:一個(gè)以網(wǎng)絡(luò)字節(jié)順序表達(dá)的32位數(shù)。
注釋:
本函數(shù)將一個(gè)32位數(shù)由網(wǎng)絡(luò)字節(jié)順序轉(zhuǎn)換為主機(jī)字節(jié)順序。
返回值:ntohl()返回一個(gè)以主機(jī)字節(jié)順序表達(dá)的數(shù)。
參見:htonl(), htons(),ntohs().
4. C語言中static函數(shù)與普通函數(shù)的區(qū)別是什么?
答:
1.static有什么用途?(請(qǐng)至少說明兩種)
1)在函數(shù)體,一個(gè)被聲明為靜態(tài)的變量在這一函數(shù)被調(diào)用過程中維持其值不變。
2) 在模塊內(nèi)(但在函數(shù)體外),一個(gè)被聲明為靜態(tài)的變量可以被模塊內(nèi)所有函數(shù)訪問,但不能被模塊外其它函數(shù)訪問。它是一個(gè)本地的全局變量。
3) 在模塊內(nèi),一個(gè)被聲明為靜態(tài)的函數(shù)只可被這一模塊內(nèi)的其它函數(shù)調(diào)用。那就是,這個(gè)函數(shù)被限制在聲明它的模塊的本地范圍內(nèi)使用
static全局變量與普通的全局變量有什么區(qū)別?static局部變量和普通局部變量有什么區(qū)別?static函數(shù)與普通函數(shù)有什么區(qū)別?
全局變量(外部變量)的說明之前再冠以static 就構(gòu)成了靜態(tài)的全局變量。全局變量本身就是靜態(tài)存儲(chǔ)方式,靜態(tài)全局變量當(dāng)然也是靜態(tài)存儲(chǔ)方式。這兩者在存儲(chǔ)方式上并無不同。這兩者的區(qū)別雖在于非靜態(tài)全局變量的作用域是整個(gè)源程序,當(dāng)一個(gè)源程序由多個(gè)源文件組成時(shí),非靜態(tài)的全局變量在各個(gè)源文件中都是有效的。而靜態(tài)全局變量則限制了其作用域,即只在定義該變量的源文件內(nèi)有效,在同一源程序的其它源文件中不能使用它。由于靜態(tài)全局變量的作用域局限于一個(gè)源文件內(nèi),只能為該源文件內(nèi)的函數(shù)公用,因此可以避免在其它源文件中引起錯(cuò)誤。從以上分析可以看出,把局部變量改變?yōu)殪o態(tài)變量后是改變了它的存儲(chǔ)方式即改變了它的生存期。把全局變量改變?yōu)殪o態(tài)變量后是改變了它的作用域,限制了它的使用范圍。
static函數(shù)與普通函數(shù)作用域不同。僅在本文件。只在當(dāng)前源文件中使用的函數(shù)應(yīng)該說明為內(nèi)部函數(shù)(static),內(nèi)部函數(shù)應(yīng)該在當(dāng)前源文件中說明和定義。對(duì)于可在當(dāng)前源文件以外使用的函數(shù),應(yīng)該在一個(gè)頭文件中說明,要使用這些函數(shù)的源文件要包含這個(gè)頭文件static全局變量與普通的全局變量有什么區(qū)別:static全局變量只初使化一次,防止在其他文件單元中被引用; static局部變量和普通局部變量有什么區(qū)別:static局部變量只被初始化一次,下一次依據(jù)上一次結(jié)果值;static函數(shù)與普通函數(shù)有什么區(qū)別:static函數(shù)在內(nèi)存中只有一份,普通函數(shù)在每個(gè)被調(diào)用中維持一份拷貝
5. 請(qǐng)實(shí)現(xiàn)內(nèi)存復(fù)制函數(shù)voidmemcpy(void *dst const void *src,int size)
原型:extern void*memcpy(void *dest, void *src, unsigned int count);
用法:#include<string.h>
功能:由src所指內(nèi)存區(qū)域復(fù)制count個(gè)字節(jié)到dest所指內(nèi)存區(qū)域。
說明:src和dest所指內(nèi)存區(qū)域不能重疊,函數(shù)返回指向dest的指針。
舉例:
// memcpy.c
#include <syslib.h>
#include <string.h>
int main(int argc, char* argv[])
{
char *s="Golden Global View";
char d[20];
clrscr();
memcpy(d,s,strlen(s));
d[strlen(s)]='\0';
printf("%s",d);
getchar();
return 0;
}
截取view
#include <string.h>
int main(int argc, char* argv[])
{
char *s="Golden Global View";
char d[20];
memcpy(d,s+14,4);
//memcpy(d,s+14*sizeof(char),4*sizeof(char));也可
d[5]='\0';
printf("%s",d);
getchar();
return 0;
}
輸出結(jié)果:
View
初始化數(shù)組
char msg[10];
memcpy(msg,0,sizeof(memcpy));
方法2:
寫一個(gè)內(nèi)存拷貝函數(shù)
// 考慮重疊的狀況
void* _memcpy(void* dest, void* src, int len)
{
if(!dest || !src || !len || dest == src)
return dest;
char* pdest = static_cast<char*>(dest);
char* psrc = static_cast<char*>(src);
// dest 在 src + len 范圍內(nèi)
if(pdest > psrc && pdest < (psrc + len))
{
// 先備份被覆蓋部分
int need = psrc + len - pdest;
int offset = pdest - psrc;
char* pcache = new char[need];
int i = 0;
for (i = 0; i < need; ++i)
pcache[i] = psrc[offset + i];
// 拷貝起始部分
for (i = 0; i < offset; ++i)
pdest[i] = psrc[i];
// 拷貝剩余部分
for (i = 0; i < need; ++i)
pdest[offset + i] = pcache[i];
delete[] pcache;
}
else
{
for (int i = 0; i < len; ++i)
pdest[i] = psrc[i];
}
return dest;
}
6.32位機(jī)器上,假設(shè)有一個(gè)32位數(shù)字0x1234abcd保存在0x00000000開始的內(nèi)存中,那么在little endian和big endian的機(jī)器上,按字節(jié)該整數(shù)在內(nèi)存中存放的順序是怎么樣的?
答:大端模式:數(shù)據(jù)的高字節(jié)存儲(chǔ)在內(nèi)存地址的低字節(jié),(正常存儲(chǔ))小端模式:數(shù)據(jù)的高字節(jié)存儲(chǔ)在內(nèi)存地址的高字節(jié).
littleendian:0x00000000-0x000000003h:cd,ab,34,12
big endian: 0x00000000-0x000000003h: 12,34,ab,cd
7.ISO七層模型是什么,tcp/udp屬于哪一層?
答:物理層-數(shù)據(jù)鏈路層-網(wǎng)絡(luò)層-傳輸層-會(huì)話層-表示層-應(yīng)用層,tcp/udp工作在傳輸層。
8.下面是一個(gè)中斷服務(wù)程序的代碼,請(qǐng)指出有那些問題?
_interrupt double compute_area(double radius)
{
double area=PI*radius*radius;
return area;
}
答:中斷子程序不能有返回值,去掉return area; compute_area之前的double關(guān)鍵字。這個(gè)函數(shù)有太多的錯(cuò)誤了,以至讓人不知從何說起了:
1)ISR 不能返回一個(gè)值。如果你不懂這個(gè),那么你不會(huì)被雇用的。
2) ISR 不能傳遞參數(shù)。如果你沒有看到這一點(diǎn),你被雇用的機(jī)會(huì)等同第一項(xiàng)。
3) 在許多的處理器/編譯器中,浮點(diǎn)一般都是不可重入的。有些處理器/編譯器需要讓額處的寄存器入棧,有些處理器/編譯器就是不允許在ISR中做浮點(diǎn)運(yùn)算。此外,ISR應(yīng)該是短而有效率的,在ISR中做浮點(diǎn)運(yùn)算是不明智的。
4) 與第三點(diǎn)一脈相承,printf()經(jīng)常有重入和性能上的問題。如果你丟掉了第三和第四點(diǎn),我不會(huì)太為難你的。不用說,如果你能得到后兩點(diǎn),那么你的被雇用前景越來越光明了。
9.多任務(wù)系統(tǒng)中,常見的任務(wù)通訊機(jī)制有哪些?
答:操作系統(tǒng)還提供進(jìn)程間的通訊機(jī)制來幫助完成這樣的任務(wù)。Linux中常見的進(jìn)程間通訊機(jī)制有:信號(hào)、管道、共享內(nèi)存、信號(hào)量和套接字等。
10.請(qǐng)實(shí)現(xiàn)內(nèi)存復(fù)制函數(shù)memcpy(void *dst,const void*src,int size).
答:
舉例:
// memcpy.c
#include <syslib.h>
#include <string.h>
int main(int argc, char* argv[])
{
char *s="Golden Global View";
char d[20];
clrscr();
memcpy(d,s,strlen(s));
d[strlen(s)]='\0';
printf("%s",d);
getchar();
return 0;
}
截取view
#include <string.h>
int main(int argc, char* argv[])
{
char *s="Golden Global View";
char d[20];
memcpy(d,s+14,4);
//memcpy(d,s+14*sizeof(char),4*sizeof(char));也可
d[5]='\0';
printf("%s",d);
getchar();
return 0;
}
輸出結(jié)果:
View
初始化數(shù)組
char msg[10];
memcpy(msg,0,sizeof(memcpy));
11.請(qǐng)列舉主流linux的發(fā)布版本(四個(gè)以上)。
答:
(1)Redhat有兩大Linux產(chǎn)品系列,其一是免費(fèi)的Fedora Core系列主要用于桌面版本,提供了較多新特性的支持。另外一個(gè)產(chǎn)品系列是收費(fèi)的Enterprise系列,這個(gè)系列分成:AS/ES/WS等分支。
(2)Advanced Server,縮寫即AS。AS在標(biāo)準(zhǔn)Linux內(nèi)核的基礎(chǔ)上,做了性能上的增強(qiáng),并提高了可靠性,集成了眾多常見服務(wù)器的驅(qū)動(dòng)程序??奢p松識(shí)別IBM/DELL/HP等常見機(jī)架式服務(wù)器的磁盤陣列卡等設(shè)備。
12.當(dāng)前l(fā)inux最主流的兩大桌面環(huán)境是什么,兩者區(qū)別是什么?
答:KDE與GNOME是目前Linux/UNIX系統(tǒng)最流行的圖形操作環(huán)境
13.linux系統(tǒng)下主要三類設(shè)備文件類型是什么?
答:塊設(shè)備、字符設(shè)備、網(wǎng)絡(luò)設(shè)備。
Linux 中的設(shè)備有2種類型:字符設(shè)備(無緩沖且只能順序存取)、塊設(shè)備(有緩沖且可以隨機(jī)存取)。每個(gè)字符設(shè)備和塊設(shè)備都必須有主、次設(shè)備號(hào),主設(shè)備號(hào)相同的設(shè)備是同類設(shè)備(使用同一個(gè)驅(qū)動(dòng)程序)。這些設(shè)備中,有些設(shè)備是對(duì)實(shí)際存在的物理硬件的抽象,而有些設(shè)備則是內(nèi)核自身提供的功能(不依賴于特定的物理硬件,又稱為"虛擬設(shè)備")。
14.以太網(wǎng)的MTU是多大?
答:通常意義上的以太網(wǎng)MTU是指沒有以太網(wǎng)header和FCS的以太網(wǎng)payload部分,IEEE802規(guī)定了大小為0~1500字節(jié);所以,二層以太網(wǎng)幀長(zhǎng)應(yīng)該為這個(gè)長(zhǎng)度加上18B(6B的DA、6B的SA和2B的Length/Etype以及4B的FCS),這樣大小應(yīng)該<1518;在Dot1Q情況下,應(yīng)該在加上4B的802.1Q的Tag,即應(yīng)該<1522B;在MPLS VPN環(huán)境中,IGP標(biāo)簽和VPN標(biāo)簽各是4B,所以,作為中間環(huán)節(jié)的交換機(jī)如果不支持Jumbo幀的話,就需要手工配置MTU=1500+N*4(N為MPLS Tag層數(shù))。
15. ARP協(xié)議作用
答:IP數(shù)據(jù)包常通過以太網(wǎng)發(fā)送。以太網(wǎng)設(shè)備并不識(shí)別32位IP地址:它們是以48位以太網(wǎng)地址傳輸以太網(wǎng)數(shù)據(jù)包的。因此,IP驅(qū)動(dòng)器必須把IP目的地址轉(zhuǎn)換成以太網(wǎng)網(wǎng)目的地址。在這兩種地址之間存在著某種靜態(tài)的或算法的映射,常常需要查看一張表。地址解析協(xié)議(Address Resolution Protocol,ARP)就是用來確定這些映象的協(xié)議。
ARP工作時(shí),送出一個(gè)含有所希望的IP地址的以太網(wǎng)廣播數(shù)據(jù)包。目的地主機(jī),或另一個(gè)代表該主機(jī)的系統(tǒng),以一個(gè)含有IP和以太網(wǎng)地址對(duì)的數(shù)據(jù)包作為應(yīng)答。發(fā)送者將這個(gè)地址對(duì)高速緩存起來,以節(jié)約不必要的ARP通信。
如果有一個(gè)不被信任的節(jié)點(diǎn)對(duì)本地網(wǎng)絡(luò)具有寫訪問許可權(quán),那么也會(huì)有某種風(fēng)險(xiǎn)。這樣一臺(tái)機(jī)器可以發(fā)布虛假的ARP報(bào)文并將所有通信都轉(zhuǎn)向它自己,然后它就可以扮演某些機(jī)器,或者順便對(duì)數(shù)據(jù)流進(jìn)行簡(jiǎn)單的修改。ARP機(jī)制常常是自動(dòng)起作用的。在特別安全的網(wǎng)絡(luò)上, ARP映射可以用固件,并且具有自動(dòng)抑制協(xié)議達(dá)到防止干擾的目的。
16. 編寫一個(gè)簡(jiǎn)單的ECHO服務(wù)器
答:如下代碼是一個(gè)簡(jiǎn)單的echo服務(wù)器,它示例的一些Winsock函數(shù)的用法。
#include <iostream>
using namespace std;
#ifdef WIN32
# include <WinSock2.h>
/// 也可在setting/liker/input/Additional dependencies加入導(dǎo)入庫(kù)引用
# pragma comment(lib, "ws2_32.lib")
/// 包含AcceptEx,TransmitFile,DisconnectEx等函數(shù)
# include <mswsock.h>
# pragma comment(lib,"Mswsock.lib")
# define PRINT_SOCKET_ERROR(FUNC)
do
{
cout << "<" << #FUNC << "> Call Error!" << ""
<< "Error Number : " << WSAGetLastError() << endl;
} while(0)
#endif // WIN32
#define PORT 5432
int main(int argc, char* argv[])
{
// = 初始化Lib庫(kù)
int nRet;
WSAData wsaData;
if ((nRet = WSAStartup(0x0202, &wsaData)) != 0)
{
PRINT_SOCKET_ERROR(WSAStartup);
return -1;
}
// = 設(shè)置監(jiān)聽socket句柄
SOCKET hListen;
/// #1
if ((hListen = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
{
PRINT_SOCKET_ERROR(socket);
return -1;
}
/// #2
SOCKADDR_IN hostAddr;
{
u_long nIp = htonl(INADDR_ANY);
{
/// 相關(guān)函數(shù)示例
char szHostName[256] = {0};
gethostname(szHostName, 256);
hostent* thisHost = gethostbyname(szHostName);
nIp = inet_addr(inet_ntoa(*((in_addr*)thisHost->h_addr_list[0])));
}
hostAddr.sin_family = AF_INET;
hostAddr.sin_port = htons(PORT);
hostAddr.sin_addr.s_addr = nIp;
}
if ((nRet = bind(hListen, (PSOCKADDR)&hostAddr, sizeof(SOCKADDR_IN))) != 0)
{
PRINT_SOCKET_ERROR(bind);
return -1;
}
/// #3
if ((nRet = listen(hListen, 5)) != 0)
{
PRINT_SOCKET_ERROR(listen);
return -1;
}
else
{
cout << "Listening at " << inet_ntoa(hostAddr.sin_addr)
<< ":" << ntohs(hostAddr.sin_port) << endl;
}
// = 處理請(qǐng)求
SOCKET hConnected;
SOCKADDR_IN remoteAddr;
int remote_addr_size = sizeof(SOCKADDR_IN);
if ((hConnected = accept(hListen, (PSOCKADDR)&remoteAddr, &remote_addr_size)) == INVALID_SOCKET)
{
PRINT_SOCKET_ERROR(accept);
return -1;
}
else
{
cout << "Connect from " << inet_ntoa(remoteAddr.sin_addr)
<< ":" << ntohs(remoteAddr.sin_port) << endl;
}
// = 數(shù)據(jù)收發(fā)
do
{
char buffer[1024] = {0};
int recv_bytes = recv(hConnected, buffer, 1024, 0);
if (recv_bytes == -1)
{
PRINT_SOCKET_ERROR(recv);
break;
}
else if (recv_bytes == 0)
{
/// 客戶端關(guān)閉了鏈接
cout << "Connection closed from " << inet_ntoa(remoteAddr.sin_addr)
<< ":" << ntohs(remoteAddr.sin_port) << endl;
closesocket(hConnected);
break;
}
else
{
buffer[recv_bytes] = 0;
cout << buffer; cout.flush();
int send_bytes = send(hConnected, buffer, recv_bytes, 0);
if (send_bytes != recv_bytes)
{
cout << "Not send out all data!" << endl;
}
}
} while (1);
closesocket(hListen);
// = 清理Lib庫(kù)
if (WSACleanup() != 0)
{
PRINT_SOCKET_ERROR(WSACleanup);
return -1;
}
return 0;
};
17. 什么是DSP?請(qǐng)簡(jiǎn)述DSP與通用CPU的差別。
答:以微處理器解度看,兩者似乎沒什么差別. 但二者所專注的鄰域卻完全不一樣. 通用的CPU專注的事務(wù)處理,對(duì)實(shí)時(shí)性的支持相對(duì)DSP差了很多.雖然一些通用CPU也在加入一些高性能的運(yùn)算支持,但它和DSP相比還是天差地遠(yuǎn).
比如現(xiàn)在的通用DSP可以在幾個(gè)us內(nèi)完成1024點(diǎn)的復(fù)數(shù)FFT,通用處理器是咋都達(dá)不到這水平(現(xiàn)在的情況),雖然其系統(tǒng)時(shí)鐘有可能比DSP高出一個(gè)數(shù)量級(jí).但一個(gè)周期完成多個(gè)復(fù)雜操作和多個(gè)周期完成一個(gè)操作的差別是很大的.
DSP完成的都是算法密集性的事務(wù),可能工作比較單一而簡(jiǎn)單,但對(duì)實(shí)時(shí)要求很高很高.必需要某個(gè)確定的時(shí)間內(nèi)(有可能就那么幾u(yù)s)完成所需要的所有操作.
通用CPU對(duì)事務(wù)管理很突出, 在這方面的能力比DSP支持得要好得多.
所以大多數(shù)的高性能系統(tǒng)會(huì)是DSP和通用CPU的結(jié)合.充分利用各自的優(yōu)點(diǎn).
由于DSP特注重高性能,其結(jié)構(gòu)在同等條件比通用CPU要復(fù)雜得多,設(shè)計(jì)上也更困難.因此其價(jià)格相比通用CPU要貴那么一些(只是通用DSP和通用CPU 相比),一些很單一功能的DSP可是很便宜的,比通用CPU還便宜. 通用DSP因?yàn)橐紤]通用,所以結(jié)構(gòu)和專用的也是不一樣的.從表面上來看,DSP與標(biāo)準(zhǔn)微處理器有許多共同的地方:一個(gè)以ALU為核心的處理器、地址和數(shù)據(jù)總線、RAM、ROM以及I/O端口,從廣義上講,DSP、微處理器和微控制器(單片機(jī))等都屬于處理器,可以說DSP是一種CPU。但DSP和一般的CPU又不同:
首先是體系結(jié)構(gòu):CPU是馮.諾伊曼結(jié)構(gòu)的,而DSP有分開的代碼和數(shù)據(jù)總線即“哈佛結(jié)構(gòu)”,這樣在同一個(gè)時(shí)鐘周期內(nèi)可以進(jìn)行多次存儲(chǔ)器訪問——這是因?yàn)?數(shù)據(jù)總線也往往有好幾組。有了這種體系結(jié)構(gòu),DSP就可以在單個(gè)時(shí)鐘周期內(nèi)取出一條指令和一個(gè)或者兩個(gè)(或者更多)的操作數(shù)。
標(biāo)準(zhǔn)化和通用性:CPU的標(biāo)準(zhǔn)化和通用性做得很好,支持操作系統(tǒng),所以以CPU為核心的系統(tǒng)方便人機(jī)交互以及和標(biāo)準(zhǔn)接口設(shè)備通信,非常方便而且不需要硬件 開發(fā)了;但這也使得CPU外設(shè)接口電路比較復(fù)雜,DSP主要還是用來開發(fā)嵌入式的信號(hào)處理系統(tǒng)了,不強(qiáng)調(diào)人機(jī)交互,一般不需要很多通信接口,因此結(jié)構(gòu)也較為簡(jiǎn)單,便于開發(fā)。如果只是著眼于嵌入式應(yīng)用的話,嵌入式CPU和DSP的區(qū)別應(yīng)該只在于一個(gè)偏重控制一個(gè)偏重運(yùn)算了。
流水線結(jié)構(gòu):大多數(shù)DSP都擁有流水結(jié)構(gòu),即每條指令都由片內(nèi)多個(gè)功能單元分別完成取指、譯碼、取數(shù)、執(zhí)行等步驟,這樣可以大大提高系統(tǒng)的執(zhí)行效率。但流水線的采用也增加了軟件設(shè)計(jì)的難度,要求設(shè)計(jì)者在程序設(shè)計(jì)中考慮流水的需要。
快速乘法器:信號(hào)處理算法往往大量用到乘加(multiply-accumulate,MAC)運(yùn)算。DSP有專用的硬件乘法器,它可以在一個(gè)時(shí)鐘周期內(nèi) 完成MAC運(yùn)算。硬件乘法器占用了DSP芯片面積的很大一部分。(與之相反,通用CPU采用一種較慢的、迭代的乘法技術(shù),它可以在多個(gè)時(shí)鐘周期內(nèi)完成一次 乘法運(yùn)算,但是占用了較少了硅片資源)。
地址發(fā)生器:DSP有專用的硬件地址發(fā)生單元,這樣它可以支持許多信號(hào)處理算法所要求的特定數(shù)據(jù)地址模式。這包括前(后)增(減)、環(huán)狀數(shù)據(jù)緩沖的模地址以及FFT的比特倒置地址。地址發(fā)生器單元與主ALU和乘法器并行工作,這就進(jìn)一步增加了DSP可以在一個(gè)時(shí)鐘周期內(nèi)可以完成的工作量。
硬件輔助循環(huán):信號(hào)處理算法常常需要執(zhí)行緊密的指令循環(huán)。對(duì)硬件輔助循環(huán)的支持,可以讓DSP高效的循環(huán)執(zhí)行代碼塊而無需讓流水線停轉(zhuǎn)或者讓軟件來測(cè)試循環(huán)終止條件。
低功耗:DSP的功耗較小,通常在0.5W到4W,采用低功耗的DSP甚至只有0.05W,可用電池供電,很適合嵌入式系統(tǒng);而CPU的功耗通常在20W以上。
18. 靜態(tài)局部變量與普通局部變量的區(qū)別是什么?
答:全局變量(外部變量)的說明之前再冠以static就構(gòu)成了靜態(tài)的全局變量。全局變量本身就是靜態(tài)存儲(chǔ)方式, 靜態(tài)全局變量當(dāng)然也是靜態(tài)存儲(chǔ)方式。 這兩者在存儲(chǔ)方式上并無不同。這兩者的區(qū)別雖在于非靜態(tài)全局變量的作用域是整個(gè)源程序,當(dāng)一個(gè)源程序由多個(gè)源文件組成時(shí),非靜態(tài)的全局變量在各個(gè)源文件中都是有效的。 而靜態(tài)全局變量則限制了其作用域, 即只在定義該變量的源文件內(nèi)有效, 在同一源程序的其它源文件中不能使用它。由于靜態(tài)全局變量的作用域局限于一個(gè)源文件內(nèi),只能為該源文件內(nèi)的函數(shù)公用,因此可以避免在其它源文件中引起錯(cuò)誤。
從以上分析可以看出,把局部變量改變?yōu)殪o態(tài)變量后是改變了它的存儲(chǔ)方式即改變了它的生存期。把全局變量改變?yōu)殪o態(tài)變量后是改變了它的作用域, 限制了它的使用范圍。
static函數(shù)與普通函數(shù)作用域不同。僅在本文件。只在當(dāng)前源文件中使用的函數(shù)應(yīng)該說明為內(nèi)部函數(shù)(static),內(nèi)部函數(shù)應(yīng)該在當(dāng)前源文件中說明和定義。對(duì)于可在當(dāng)前源文件以外使用的函數(shù),應(yīng)該在一個(gè)頭文件中說明,要使用這些函數(shù)的源文件要包含這個(gè)頭文件
static全局變量與普通的全局變量有什么區(qū)別:static全局變量只初使化一次,防止在其他文件單元中被引用;static局部變量和普通局部變量有什么區(qū)別:static局部變量只被初始化一次,下一次依據(jù)上一次結(jié)果值;static函數(shù)與普通函數(shù)有什么區(qū)別:static函數(shù)在內(nèi)存中只有一份,普通函數(shù)在每個(gè)被調(diào)用中維持一份拷貝。程序的局部變量存在于(堆棧)中,全局變量存在于(靜態(tài)區(qū) )中,動(dòng)態(tài)申請(qǐng)數(shù)據(jù)存在于( 堆)中。
19.請(qǐng)說明DSP中定點(diǎn)、浮點(diǎn)的概念
答:定點(diǎn)數(shù)指小數(shù)點(diǎn)在數(shù)中的位置是固定不變的,通常有定點(diǎn)整數(shù)和定點(diǎn)小數(shù)。在對(duì)小數(shù)點(diǎn)位置作出選擇之后,運(yùn)算中的所有數(shù)均應(yīng)統(tǒng)一為定點(diǎn)整數(shù)或定點(diǎn)小數(shù),在運(yùn)算中不再考慮小數(shù)問題。
(1)定義:數(shù)據(jù)中小數(shù)點(diǎn)位置固定不變的數(shù) (2)種類:定點(diǎn)整數(shù)(3)小數(shù)點(diǎn)在符號(hào)位與有效位之間。
注:定點(diǎn)數(shù)受字長(zhǎng)的限制,超出范圍會(huì)有溢出。
20.定點(diǎn)數(shù)與浮點(diǎn)數(shù)區(qū)別
答:定點(diǎn)表示法運(yùn)算直觀,但數(shù)的表示范圍較小,不同的數(shù)運(yùn)算時(shí)要考慮比例因子的選取,以防止溢出。浮點(diǎn)表示法運(yùn)算時(shí)可以不考慮溢出,但浮點(diǎn)運(yùn)算,編程較難。要掌握定、浮點(diǎn)數(shù)的轉(zhuǎn)換方法及浮點(diǎn)數(shù)規(guī)格化方法。
21.什么是cache?cache有哪些操作?
答:cache n. 高速緩沖存儲(chǔ)器 一種特殊的存儲(chǔ)器子系統(tǒng),其中復(fù)制了頻繁使用的數(shù)據(jù)以利于快速訪問。存儲(chǔ)器的高速緩沖存儲(chǔ)器存儲(chǔ)了頻繁訪問的 RAM 位置的內(nèi)容及這些數(shù)據(jù)項(xiàng)的存儲(chǔ)地址。當(dāng)處理器引用存儲(chǔ)器中的某地址時(shí),高速緩沖存儲(chǔ)器便檢查是否存有該地址。如果存有該地址,則將數(shù)據(jù)返回處理器;如果沒有保存該地址,則進(jìn)行常規(guī)的存儲(chǔ)器訪問。因?yàn)楦咚倬彌_存儲(chǔ)器總是比主RAM 存儲(chǔ)器速度快,所以當(dāng) RAM 的訪問速度低于微處理器的速度時(shí),常使用高速緩沖存儲(chǔ)器。
*博客內(nèi)容為網(wǎng)友個(gè)人發(fā)布,僅代表博主個(gè)人觀點(diǎn),如有侵權(quán)請(qǐng)聯(lián)系工作人員刪除。