嵌入式經典面試題


1. 關鍵字volatile有什么含意 並給出三個不同的例子。
 
一個定義為volatile的變量是說這變量可能會被意想不到地改變,這樣,編譯器就不會去假設這個變量的值了。 精確地說就是,優化器在用到這個變量時必須每次都小心地重新讀取這個變量的值 ,而不是使用保存在寄存器里的備份。下面 是volatile變量的幾個例子:
1). 並行設備的硬件寄存器(如:狀態寄存器)
2). 一個中斷服務子程序中會訪問到的非自動變量(Non-automatic variables)
3). 多線程應用中被幾個任務共享的變量
 
 
2, 一個指針可以是volatile 嗎?解釋為什么。
2). 是的。盡管這並不很常見。一個例子是當一個中服務子程序修該一個指向一個buffer的指針時。
 
9. 嵌入式系統總是要用戶對變量或寄存器進行位操作。給定一個整型變量a,寫兩段代碼,第一個設置a的bit 3,第二個清除a 的bit 3。在以上兩個操作中,要保持其它位不變。
#define BIT3 (0x1<<3)
static int a;
void set_bit3(void)
{
a |= BIT3;
}
void clear_bit3(void)
{
a &= ~BIT3;
}
一些人喜歡為設置和清除值而定義一個掩碼同時定義一些說明常數,這也是可以接受的。我希望看到幾個要點: 說明常數、|=和&=~操作
 
 
11. 中斷是嵌入式系統中重要的組成部分,這導致了很多編譯開發商提供一種擴展—讓標准C支持中斷。具代表事實是,產生了一個新的關鍵字 __interrupt。下面的代碼就使用了__interrupt關鍵字去定義了一個中斷服務子程序(ISR),請評論一下這段代碼的。
 
__interrupt double compute_area (double radius)
{
double area = PI * radius * radius;
printf(" Area = %f", area);
return area;
這個函數有太多的錯誤了,以至讓人不知從何說起了:
1). ISR 不能返回一個值。如果你不懂這個,那么你不會被雇用的。
2). ISR 不能傳遞參數。如果你沒有看到這一點,你被雇用的機會等同第一項。
3). 在許多的處理器/編譯器中,浮點一般都是不可重入的。有些處理器/編譯器需要讓額處的寄存器入棧,有些處理器/編譯器就是不允許在ISR中做浮點運算。此外,ISR應該是短而有效率的,在ISR中做浮點運算是不明智的
4). 與第三點一脈相承,printf()經常有重入和性能上的問題。如果你丟掉了第三和第四點,我不會太為難你的。不用說,如果你能得到后兩點,那么你的被雇用前景越來越光明了。
 
13. 評價下面的代碼片斷:
 
unsigned int zero = 0;
unsigned int compzero = 0xFFFF;
/*1's complement of zero */
 
對於一個int型不是16位的處理器為說,上面的代碼是不正確的。應編寫如下:
 
unsigned int compzero = ~0;
 
這一問題真正能揭露出應試者是否懂得處理器字長的重要性。在我的經驗里,好的嵌入式程序員非常准確地明白硬件的細節和它的局限,然而PC機程序往往把硬件作為一個無法避免的煩惱。
到了這個階段,應試者或者完全垂頭喪氣了或者信心滿滿志在必得。如果顯然應試者不是很好,那么這個測試就在這里結束了。但如果顯然應試者做得不錯,那么我就扔出下面的追加問題,這些問題是比較難的,我想僅僅非常優秀的應試者能做得不錯。提出這些問題,我希望更多看到應試者應付問題的方法,而不是答案。不管如何,你就當是這個娛樂吧…
}
 
 
 
1、線形表a、b為兩個有序升序的線形表,編寫一程序,使兩個有序線形表合並成一個有序升序線形表h;
 
 
答案在 請化大學 嚴銳敏《數據結構第二版》第二章例題,數據結構當中,這個叫做:兩路歸並排序
Linklist *unio(Linklist *p,Linklist *q){
linklist *R,*pa,*qa,*ra;
pa=p;
qa=q;
R=ra=p;
while(pa->next!=NULL&&qa->next!=NULL){
if(pa->data>qa->data){
ra->next=qa;
qa=qa->next;
}
else{
ra->next=pa;
pa=pa->next;
}
}
if(pa->next!=NULL)
ra->next=pa;
if(qa->next!=NULL)
ra->next==qa;
return R;
}
 
 
3、用遞歸算法判斷數組a[N]是否為一個遞增數組。
遞歸的方法,記錄當前最大的,並且判斷當前的是否比這個還大,大則繼續,否則返回false結束:
bool fun( int a[], int n )
{
if( n= =1 )
return true;
if( n= =2 )
return a[n-1] >= a[n-2];
return fun( a,n-1) && ( a[n-1] >= a[n-2] );
}
 
 
2.單連表的建立,把'a'--'z'26個字母插入到連表中,並且倒敘,還要打印!
方法1:
typedef struct val
{    int date_1;
     struct val *next;
}*p;
 
void main(void)
{    char c;
    
     for(c=122;c>=97;c--)
        { p.date=c;
          p=p->next;
         }
 
     p.next=NULL;
}
}
方法2:
node *p = NULL;
node *q = NULL;
 
node *head = (node*)malloc(sizeof(node));
head->data = ' ';head->next=NULL;
 
node *first = (node*)malloc(sizeof(node));
first->data = 'a';first->next=NULL;head->next = first;
p = first;
 
int longth = 'z' - 'b';
int i=0;
while ( i<=longth )
{
node *temp = (node*)malloc(sizeof(node));
temp->data = 'b'+i;temp->next=NULL;q=temp;
 
head->next = temp; temp->next=p;p=q;
i++;
}
 
print(head);
 
 
一個遞規反向輸出字符串的例子,可謂是反序的經典例程.
 
void inverse(char *p)
{
     if( *p = = '\0' )
return;
     inverse( p+1 );
     printf( "%c", *p );
}
 
int main(int argc, char *argv[])
{
     inverse("abc\0");
 
     return 0;
}
2。運行的結果為什么等於15
 
#include "stdio.h"
#include "string.h"
 
void main()
{
 
char aa[10];
printf("%d",strlen(aa));
}
 
答案:sizeof()和初不初始化,沒有關系;strlen()和初始化有關。
 
 
6。int a,b,c 請寫函數實現C=a+b ,不可以改變數據類型,如將c改為long int,關鍵是如何處理溢出問題
答案:bool add (int a, int b,int *c)
{
*c=a+b;
return (a>0 && b>0 &&(*c<a || *c<b) || (a<0 && b<0 &&(*c>a || *c>b))) ;
}
 
 
7。分析:
struct bit
{    int a:3;
     int b:2;
     int c:3;
};
int main()
{
   bit s;
   char *c=(char*)&s;
    cout<<sizeof(bit)<<endl;
   *c=0x99;
    cout << s.a <<endl <<s.b<<endl<<s.c<<endl;
      int a=-1;
    printf("%x",a);
   return 0;
}
輸出為什么是?
 
答案:4
1
-1
-4
ffffffff
因為0x99在內存中表示為 100 11 001 , a = 001, b = 11, c = 100(在vc環境中,一般是由右到左進行分配的)
當c為有符合數時, c = 100, 最高1為表示c為負數,負數在計算機用補碼表示,所以c = -4;同理
b = -1;
當c為有符合數時, c = 100,即 c = 4,同理 b = 3
 
 
9。下面這個程序執行后會有什么錯誤或者效果:
#define MAX 255
int main()
{
    unsigned char A[MAX], i ; //i被定義為unsigned char
    for (i=0;i<=MAX;i++)
       A[i]=i;
}
 
 
答案: 死循環加數組越界訪問(C/C++不進行數組越界檢查)
MAX=255
數組A的下標范圍為:0..MAX-1,這是其一..
其二.當i循環到255時,循環內執行:
   A[255]=255;
這句本身沒有問題..但是返回for (i=0;i<=MAX;i++)語句時,
由於unsigned char的取值范圍在(0..255),i++以后i又為0了..無限循環下去 .
 
 
2. 對於一個頻繁使用的短小函數 , C 語言中應用什么實現 , C++ 中應用什么實現 ?
c 用宏定義, c++ inline
 
6. 軟件測試都有那些種類 ?
黑盒:針對系統功能的測試     白合:測試函數功能,各函數接口
 
  1. 進程和線程的差別。
線程是指進程內的一個執行單元 , 也是進程內的可調度實體 .
與進程的區別 :
(1) 調度:線程作為調度和分配的基本單位,進程作為擁有資源的基本單位
(2) 並發性:不僅進程之間可以並發執行,同一個進程的多個線程之間也可並發執行
(3) 擁有資源:進程是擁有資源的一個獨 - 立單位,線程不擁有系統資源,但可以訪問隸屬於進程的資源 .
(4) 系統開銷:在創建或撤消進程時,由於系統都要為之分配和回收資源,導致系統的開銷明顯大於創建或撤消線程時的開銷。
 
11. 進程死鎖的原因
資源競爭及進程推進順序非法
12. 死鎖的 4 個必要條件
互斥、請求保持、不可剝奪、環路
13. 死鎖的處理
鴕鳥策略、預防策略、避免策略、檢測與解除死鎖
 
 
9. 純虛函數如何定義?使用時應注意什么?
virtual void f()=0;
是接口,子類必須要實現
 
 
2:int main()
   {
    int x=3;
    printf("%d",x);
    return 1;
  
   }
問函數既然不會被其它函數調用,為什么要返回1?
mian中,c標准認為0表示成功,非0表示錯誤。具體的值是某中具體出錯信息
  1. 要對絕對地址0x100000賦值,我們可以用
(unsigned int*)0x100000 = 1234;
那么要是想讓程序跳轉到絕對地址是 0x100000 去執行,應該怎么做?
*((void (*)( ))0x100000 ) ( );
首先要將 0x100000 強制轉換成函數指針 , :
(void (*)())0x100000
然后再調用它 :
*((void (*)())0x100000)();
typedef 可以看得更直觀些 :
typedef void(*)() voidFuncPtr;
*((voidFuncPtr)0x100000)();
 
 
位域:  
有些信息在存儲時,並不需要占用一個完整的字節,而只需占幾個或一個二進制位。例如在存放一個開關量時,只有0和1 兩種狀態,用一位二進位即可。為了節省存儲空間,並使處理簡便,C語言又提供了一種數據結構,稱為“位域”或“位段”。所謂“位域”是把一個字節中的二進位划分為幾個不同的區域,並說明每個區域的位數。每個域有一個域名,允許在程序中按域名進行操作。這樣就可以把幾個不同的對象用一個字節的二進制位域來表示。一、位域的定義和位域變量的說明位域定義與結構定義相仿,其形式為:    
struct 位域結構名    
{ 位域列表 };   
其中位域列表的形式為:類型說明符位域名:位域長度    
例如:    
struct bs   
{   
int a:8;   
int b:2;   
int c:6;   
};   
位域變量的說明與結構變量說明的方式相同。可采用先定義后說明,同時定義說明或者直接說明這三種方式。例如:    
struct bs   
{   
int a:8;   
int b:2;   
int c:6;   
}data;   
說明data為bs變量,共占兩個字節。其中位域a占8位,位域b占2位,位域c占6位。對於位域的定義尚有以下幾點說明:   
1. 一個位域必須存儲在同一個字節中,不能跨兩個字節。如一個字節所剩空間不夠存放另一位域時,應從下一單元起存放該位域。也可以有意使某位域從下一單元開始。例如:    
struct bs   
{   
unsigned a:4   
unsigned :0 /*空域*/   
unsigned b:4 /*從下一單元開始存放*/   
unsigned c:4   
}   
在這個位域定義中,a占第一字節的4位,后4位填0表示不使用,b從第二字節開始,占用4位,c占用4位。
2. 由於位域不允許跨兩個字節,因此位域的長度不能大於一個字節的長度,也就是說不能超過8位二進位。   
3. 位域可以無位域名,這時它只用來作填充或調整位置。無名的位域是不能使用的。例如:    
struct k   
{   
int a:1   
int :2 /*該2位不能使用*/   
int b:3   
int c:2   
};   
從以上分析可以看出,位域在本質上就是一種結構類型,不過其成員是按二進位分配的。   
二、位域的使用位域的使用和結構成員的使用相同,其一般形式為:位域變量名•位域名位域允許用各種格式輸出。   
main(){   
struct bs   
{   
unsigned a:1;   
unsigned b:3;   
unsigned c:4;   
} bit,*pbit;   
bit.a=1;   
bit.b=7;   
bit.c=15;   
pri
 
1、頭文件中的 ifndef/define/endif 干什么用?(5分)
答:防止該頭文件被重復引用。
 
(2)strcpy能把strSrc的內容復制到strDest,為什么還要char * 類型的返回值?
答:為了實現鏈式表達式。
 
六、編寫類String的構造函數、析構函數和賦值函數(25分)
已知類String的原型為:
    class String
    {
      public:
       String(const char *str = NULL); // 普通構造函數
       String(const String &other);        // 拷貝構造函數
       ~ String(void);                     // 析構函數
       String & operate =(const String &other);  // 賦值函數
      private:
       char   *m_data;             // 用於保存字符串
    };
    請編寫String的上述4個函數。
標准答案:
// String的析構函數
   String::~String(void)               // 3分
{
  delete [] m_data;                      
// 由於m_data是內部數據類型,也可以寫成 delete m_data;
   }
    // String的普通構造函數            
   String::String(const char *str)      // 6分
{
  if(str==NULL)                         
  {
     m_data = new char[1];    // 若能加 NULL 判斷則更好
     *m_data = ‘\0’;                     
  }                                        
  else
  {
     int length = strlen(str);          
     m_data = new char[length+1];  // 若能加 NULL 判斷則更好     
     strcpy(m_data, str);               
  }
}
// 拷貝構造函數
   String::String(const String &other)   // 3分
   { 
  int length = strlen(other.m_data);
  m_data = new char[length+1];      // 若能加 NULL 判斷則更好   
  strcpy(m_data, other.m_data);        
}
// 賦值函數
   String & String::operate =(const String &other)    // 13分
   { 
      // (1) 檢查自賦值                     // 4分
      if(this == &other)
         return *this;
  
// (2) 釋放原有的內存資源            // 3分
      delete [] m_data;
     
      // (3)分配新的內存資源,並復制內容 // 3分
  int length = strlen(other.m_data);
  m_data = new char[length+1];         // 若能加 NULL 判斷則更好
      strcpy(m_data, other.m_data);
     
      // (4)返回本對象的引用            // 3分
      return *this;
}
 
 

<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">






免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM