C/C++筆試題 (一)

1.static有什麼用途?(請至少說明兩種)
    1)在函數體,一個被聲明爲靜態的變量在這一函數被調用過程中維持其值不變。
    2) 在模塊內(但在函數體外),一個被聲明爲靜態的變量可以被模塊內所用函數訪問,但不能被模塊外其它函數訪問。它是一個本地的全局變量。
    3) 在模塊內,一個被聲明爲靜態的函數只可被這一模塊內的其它函數調用。那就是,這個函數被限制在聲明它的模塊的本地範圍內使用

2.引用與指針有什麼區別?
    1) 引用必須被初始化,指針不必。
    2) 引用初始化以後不能被改變,指針可以改變所指的對象。
    3) 不存在指向空值的引用,但是存在指向空值的指針。

3.描述實時系統的基本特性
       在特定時間內完成特定的任務,實時性與可靠性。

4.全局變量和局部變量在內存中是否有區別?如果有,是什麼區別?
      全局變量儲存在靜態數據庫,局部變量在堆棧。

5.什麼是平衡二叉樹?
      左右子樹都是平衡二叉樹 且左右子樹的深度差值的絕對值不大於1。

6.堆棧溢出一般是由什麼原因導致的?
      沒有回收垃圾資源。

7.什麼函數不能聲明爲虛函數?
      constructor函數不能聲明爲虛函數。

8.冒泡排序算法的時間複雜度是什麼?
      時間複雜度是O(n^2)。

9.寫出float x 與“零值”比較的if語句。
      if(x>0.000001&&x<-0.000001)

10.Internet採用哪種網絡協議?該協議的主要層次結構?
      Tcp/Ip協議
      主要層次結構爲: 應用層/傳輸層/網絡層/數據鏈路層/物理層。

11.Internet物理地址和IP地址轉換採用什麼協議?
      ARP (Address Resolution Protocol)(地址解析協議)

12.IP地址的編碼分爲哪倆部分?
     IP地址由兩部分組成,網絡號和主機號。不過是要和“子網掩碼”按位與上之後才能區分哪些是網絡位哪些是主機位。

13.用戶輸入M,N值,從1至N開始順序循環數數,每數到M輸出該數值,直至全部輸出。寫出C程序。
     循環鏈表,用取餘操作做


14.不能做switch()的參數類型是:
     switch的參數不能爲實型。

1.寫出判斷ABCD四個表達式的是否正確, 若正確, 寫出經過表達式中 a的值(3分)
int a = 4;
(A)a += (a++); (B) a += (++a) ;(C) (a++) += a;(D) (++a) += (a++);
a = ?
答:C錯誤,左側不是一個有效變量,不能賦值,可改爲(++a) += a;
改後答案依次爲9,10,10,11

2.某32位系統下, C++程序,請計算sizeof 的值(5分).
char str[] = “http://www.ibegroup.com/”
char *p = str ;
int n = 10;
請計算
sizeof (str ) = ?(1)
sizeof ( p ) = ?(2)
sizeof ( n ) = ?(3)
void Foo ( char str[100]){
請計算
sizeof( str ) = ?(4)
}
void *p = malloc( 100 );
請計算
sizeof ( p ) = ?(5)
答:(1)17 (2)4 (3) 4 (4)4 (5)4

3. 回答下面的問題. (4分)
(1).頭文件中的 ifndef/define/endif 幹什麼用?預處理
答:防止頭文件被重複引用
(2). #i nclude 和 #i nclude “filename.h” 有什麼區別?
答:前者用來包含開發環境提供的庫頭文件,後者用來包含自己編寫的頭文件。
(3).在C++ 程序中調用被 C 編譯器編譯後的函數,爲什麼要加 extern “C”聲明?
答:函數和變量被C++編譯後在符號庫中的名字與C語言的不同,被extern "C"修飾的變
量和函數是按照C語言方式編譯和連接的。由於編譯後的名字不同,C++程序不能直接調
用C 函數。C++提供了一個C 連接交換指定符號extern“C”來解決這個問題。
(4). switch()中不允許的數據類型是?
答:實型

4. 回答下面的問題(6分)
(1).Void GetMemory(char **p, int num){
*p = (char *)malloc(num);
}
void Test(void){
char *str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf(str);
}
請問運行Test 函數會有什麼樣的結果?
答:輸出“hello”
(2). void Test(void){
char *str = (char *) malloc(100);
strcpy(str, “hello”);
free(str);
if(str != NULL){
strcpy(str, “world”);
printf(str);
}
}
請問運行Test 函數會有什麼樣的結果?
答:輸出“world”
(3). char *GetMemory(void){
char p[] = "hello world";
return p;
}
void Test(void){
char *str = NULL;
str = GetMemory();
printf(str);
}
請問運行Test 函數會有什麼樣的結果?
答:無效的指針,輸出不確定

5. 編寫strcat函數(6分)
已知strcat函數的原型是char *strcat (char *strDest, const char *strSrc);
其中strDest 是目的字符串,strSrc 是源字符串。
(1)不調用C++/C 的字符串庫函數,請編寫函數 strcat
答:
VC源碼:
char * __cdecl strcat (char * dst, const char * src)
{
char * cp = dst;
while( *cp )
cp++; /* find end of dst */
while( *cp++ = *src++ ) ; /* Copy src to end of dst */
return( dst ); /* return dst */
}
(2)strcat能把strSrc 的內容連接到strDest,爲什麼還要char * 類型的返回值?
答:方便賦值給其他變量

6.MFC中CString是類型安全類麼?
答:不是,其它數據類型轉換到CString可以使用CString的成員函數Format來轉換

7.C++中爲什麼用模板類。
答:(1)可用來創建動態增長和減小的數據結構
(2)它是類型無關的,因此具有很高的可複用性。
(3)它在編譯時而不是運行時檢查數據類型,保證了類型安全
(4)它是平臺無關的,可移植性
(5)可用於基本數據類型

8.CSingleLock是幹什麼的。
答:同步多個線程對一個數據類的同時訪問

9.NEWTEXTMETRIC 是什麼。
答:物理字體結構,用來設置字體的高寬大小

10.程序什麼時候應該使用線程,什麼時候單線程效率高。
答:1.耗時的操作使用線程,提高應用程序響應
2.並行操作時使用線程,如C/S架構的服務器端併發線程響應用戶的請求。
3.多CPU系統中,使用線程提高CPU利用率
4.改善程序結構。一個既長又複雜的進程可以考慮分爲多個線程,成爲幾個獨立或半獨
立的運行部分,這樣的程序會利於理解和修改。
其他情況都使用單線程。

11.Windows是內核級線程麼。
答:見下一題

12.Linux有內核級線程麼。
答:線程通常被定義爲一個進程中代碼的不同執行路線。從實現方式上劃分,線程有兩
種類型:“用戶級線程”和“內核級線程”。 用戶線程指不需要內核支持而在用戶程序
中實現的線程,其不依賴於操作系統核心,應用進程利用線程庫提供創建、同步、調度
和管理線程的函數來控制用戶線程。這種線程甚至在象 DOS 這樣的操作系統中也可實現
,但線程的調度需要用戶程序完成,這有些類似 Windows 3.x 的協作式多任務。另外一
種則需要內核的參與,由內核完成線程的調度。其依賴於操作系統核心,由內核的內部
需求進行創建和撤銷,這兩種模型各有其好處和缺點。用戶線程不需要額外的內核開支
,並且用戶態線程的實現方式可以被定製或修改以適應特殊應用的要求,但是當一個線
程因 I/O 而處於等待狀態時,整個進程就會被調度程序切換爲等待狀態,其他線程得不
到運行的機會;而內核線程則沒有各個限制,有利於發揮多處理器的併發優勢,但卻佔
用了更多的系統開支。 
Windows NT和OS/2支持內核線程。Linux 支持內核級的多線程

13.C++中什麼數據分配在棧或堆中,New分配數據是在近堆還是遠堆中?
答:棧: 存放局部變量,函數調用參數,函數返回值,函數返回地址。由系統管理
堆: 程序運行時動態申請,new 和 malloc申請的內存就在堆上

14.使用線程是如何防止出現大的波峯。
答:意思是如何防止同時產生大量的線程,方法是使用線程池,線程池具有可以同時提
高調度效率和限制資源使用的好處,線程池中的線程達到最大數時,其他線程就會排隊
等候。

15函數模板與類模板有什麼區別?
答:函數模板的實例化是由編譯程序在處理函數調用時自動完成的,而類模板的實例化
必須由程序員在程序中顯式地指定。

16一般數據庫若出現日誌滿了,會出現什麼情況,是否還能使用?
答:只能執行查詢等讀操作,不能執行更改,備份等寫操作,原因是任何寫操作都要記
錄日誌。也就是說基本上處於不能使用的狀態。

17 SQL Server是否支持行級鎖,有什麼好處?
答:支持,設立封鎖機制主要是爲了對併發操作進行控制,對干擾進行封鎖,保證數據
的一致性和準確性,行級封鎖確保在用戶取得被更新的行到該行進行更新這段時間內不
被其它用戶所修改。因而行級鎖即可保證數據的一致性又能提高數據操作的迸發性。

18如果數據庫滿了會出現什麼情況,是否還能使用?
答:見16

19 關於內存對齊的問題以及sizof()的輸出 
答:編譯器自動對齊的原因:爲了提高程序的性能,數據結構(尤其是棧)應該儘可能
地在自然邊界上對齊。原因在於,爲了訪問未對齊的內存,處理器需要作兩次內存訪問
;然而,對齊的內存訪問僅需要一次訪問。

20 int i=10, j=10, k=3; k*=i+j; k最後的值是?
答:60,此題考察優先級,實際寫成: k*=(i+j);,賦值運算符優先級最低

21.對數據庫的一張表進行操作,同時要對另一張表進行操作,如何實現?
答:將操作多個表的操作放入到事務中進行處理

22.TCP/IP 建立連接的過程?(3-way shake)
答:在TCP/IP協議中,TCP協議提供可靠的連接服務,採用三次握手建立一個連接。
  第一次握手:建立連接時,客戶端發送syn包(syn=j)到服務器,並進入SYN_SEND狀
態,等待服務器確認;
第二次握手:服務器收到syn包,必須確認客戶的SYN(ack=j+1),同時自己也發送一個
SYN包(syn=k),即SYN+ACK包,此時服務器進入SYN_RECV狀態;
  第三次握手:客戶端收到服務器的SYN+ACK包,向服務器發送確認包ACK(ack=k+1)
,此包發送完畢,客戶端和服務器進入ESTABLISHED狀態,完成三次握手。

23.ICMP是什麼協議,處於哪一層?
答:Internet控制報文協議,處於網絡層(IP層)

24.觸發器怎麼工作的?
答:觸發器主要是通過事件進行觸發而被執行的,當對某一表進行諸如UPDATE、 INSERT
、 DELETE 這些操作時,數據庫就會自動執行觸發器所定義的SQL 語句,從而確保對數
據的處理必須符合由這些SQL 語句所定義的規則。

25.winsock建立連接的主要實現步驟?
答:服務器端:socker()建立套接字,綁定(bind)並監聽(listen),用accept()
等待客戶端連接。
客戶端:socker()建立套接字,連接(connect)服務器,連接上後使用send()和recv(
),在套接字上寫讀數據,直至數據交換完畢,closesocket()關閉套接字。
服務器端:accept()發現有客戶端連接,建立一個新的套接字,自身重新開始等待連
接。該新產生的套接字使用send()和recv()寫讀數據,直至數據交換完畢,closesock
et()關閉套接字。

26.動態連接庫的兩種方式?
答:調用一個DLL中的函數有兩種方法:
1.載入時動態鏈接(load-time dynamic linking),模塊非常明確調用某個導出函數
,使得他們就像本地函數一樣。這需要鏈接時鏈接那些函數所在DLL的導入庫,導入庫向
系統提供了載入DLL時所需的信息及DLL函數定位。 
2.運行時動態鏈接(run-time dynamic linking),運行時可以通過LoadLibrary或Loa
dLibraryEx函數載入DLL。DLL載入後,模塊可以通過調用GetProcAddress獲取DLL函數的
出口地址,然後就可以通過返回的函數指針調用DLL函數了。如此即可避免導入庫文件了

27.IP組播有那些好處?
答:Internet上產生的許多新的應用,特別是高帶寬的多媒體應用,帶來了帶寬的急劇
消耗和網絡擁擠問題。組播是一種允許一個或多個發送者(組播源)發送單一的數據包
到多個接收者(一次的,同時的)的網絡技術。組播可以大大的節省網絡帶寬,因爲無
論有多少個目標地址,在整個網絡的任何一條鏈路上只傳送單一的數據包。所以說組播
技術的核心就是針對如何節約網絡資源的前提下保證服務質量。

轉自:http://www.cnblogs.com/bluespot/archive/2008/03/11/1100661.html ->

『C/C++面試題大彙總』


最近因爲找工作,收集了很多C語言方面方面的面試題以及答案。現在新工作搞定了,決定把這些資料發出來,送給有需要的朋友,免得再象我一樣到處搜尋,實在辛苦。

發佈之前先申明兩點:
    1 所有資料來自網絡(主要是CSDN),本人只是收集和轉發。
    2 所有問題解答(尤其是代碼)只是參考,不保證正確。

先發基本問題,再發編程問題..........

想成爲嵌入式程序員應知道的0x10個基本問題:
預處理器(Preprocessor)

1 . 用預處理指令#define 聲明一個常數,用以表明1年中有多少秒(忽略閏年問題)
         #define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL
我在這想看到幾件事情:
1) #define 語法的基本知識(例如:不能以分號結束,括號的使用,等等)
2)懂得預處理器將爲你計算常數表達式的值,因此,直接寫出你是如何計算一年中有多少秒而不是計算出實際的值,是更清晰而沒有代價的。
3) 意識到這個表達式將使一個16位機的整型數溢出-因此要用到長整型符號L,告訴編譯器這個常數是的長整型數。
4) 如果你在你的表達式中用到UL(表示無符號長整型),那麼你有了一個好的起點。記住,第一印象很重要。

2 . 寫一個"標準"宏MIN ,這個宏輸入兩個參數並返回較小的一個。
        #define MIN(A,B) ((A) <= (B) ? (A) : (B)) 
這個測試是爲下面的目的而設的:
1) 標識#define在宏中應用的基本知識。這是很重要的。因爲在 嵌入(inline)操作符 變爲標準C的一部分之前,宏是方便產生嵌入代碼的唯一方法,對於嵌入式系統來說,爲了能達到要求的性能,嵌入代碼經常是必須的方法。
2)三重條件操作符的知識。這個操作符存在C語言中的原因是它使得編譯器能產生比if-then-else更優化的代碼,瞭解這個用法是很重要的。
3) 懂得在宏中小心地把參數用括號括起來
4) 我也用這個問題開始討論宏的副作用,例如:當你寫下面的代碼時會發生什麼事?
        least = MIN(*p++, b);

3. 預處理器標識#error的目的是什麼?
如果你不知道答案,請看參考文獻1。這問題對區分一個正常的夥計和一個書呆子是很有用的。只有書呆子纔會讀C語言課本的附錄去找出象這種問題的答案。當然如果你不是在找一個書呆子,那麼應試者最好希望自己不要知道答案。


死循環(Infinite loops)

4. 嵌入式系統中經常要用到無限循環,你怎麼樣用C編寫死循環呢?
這個問題用幾個解決方案。我首選的方案是:

while(1)
{

}

一些程序員更喜歡如下方案:

for(;;)
{

}

這個實現方式讓我爲難,因爲這個語法沒有確切表達到底怎麼回事。如果一個應試者給出這個作爲方案,我將用這個作爲一個機會去探究他們這樣做的基本原理。如果他們的基本答案是:"我被教着這樣做,但從沒有想到過爲什麼。"這會給我留下一個壞印象。

三個方案是用 goto
Loop:
...
goto Loop;
應試者如給出上面的方案,這說明或者他是一個彙編語言程序員(這也許是好事)或者他是一個想進入新領域的BASIC/FORTRAN程序員。


數據聲明(Data declarations)

5. 用變量a給出下面的定義
a) 一個整型數(An integer) 
b)一個指向整型數的指針( A pointer to an integer) 
c)一個指向指針的的指針,它指向的指針是指向一個整型數( A pointer to a pointer to an intege)r 
d)一個有10個整型數的數組( An array of 10 integers) 
e) 一個有10個指針的數組,該指針是指向一個整型數的。(An array of 10 pointers to integers) 
f) 一個指向有10個整型數數組的指針( A pointer to an array of 10 integers) 
g) 一個指向函數的指針,該函數有一個整型參數並返回一個整型數(A pointer to a function that takes an integer as an argument and returns an integer) 
h) 一個有10個指針的數組,該指針指向一個函數,該函數有一個整型參數並返回一個整型數( An array of ten pointers to functions that take an integer argument and return 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 integer argument and return an integer

人們經常聲稱這裏有幾個問題是那種要翻一下書才能回答的問題,我同意這種說法。當我寫這篇文章時,爲了確定語法的正確性,我的確查了一下書。但是當我被面試的時候,我期望被問到這個問題(或者相近的問題)。因爲在被面試的這段時間裏,我確定我知道這個問題的答案。應試者如果不知道所有的答案(或至少大部分答案),那麼也就沒有爲這次面試做準備,如果該面試者沒有爲這次面試做準備,那麼他又能爲什麼出準備呢?

Static

6. 關鍵字static的作用是什麼?
這個簡單的問題很少有人能回答完全。在C語言中,關鍵字static有三個明顯的作用:
1)在函數體,一個被聲明爲靜態的變量在這一函數被調用過程中維持其值不變。
2) 在模塊內(但在函數體外),一個被聲明爲靜態的變量可以被模塊內所用函數訪問,但不能被模塊外其它函數訪問。它是一個本地的全局變量。
3) 在模塊內,一個被聲明爲靜態的函數只可被這一模塊內的其它函數調用。那就是,這個函數被限制在聲明它的模塊的本地範圍內使用。

大多數應試者能正確回答第一部分,一部分能正確回答第二部分,同是很少的人能懂得第三部分。這是一個應試者的嚴重的缺點,因爲他顯然不懂得本地化數據和代碼範圍的好處和重要性。

Const

7.關鍵字const有什麼含意?
我只要一聽到被面試者說:"const意味着常數",我就知道我正在和一個業餘者打交道。去年Dan Saks已經在他的文章裏完全概括了const的所有用法,因此ESP(譯者:Embedded Systems Programming)的每一位讀者應該非常熟悉const能做什麼和不能做什麼.如果你從沒有讀到那篇文章,只要能說出const意味着"只讀"就可以了。儘管這個答案不是完全的答案,但我接受它作爲一個正確的答案。(如果你想知道更詳細的答案,仔細讀一下Saks的文章吧。)
如果應試者能正確回答這個問題,我將問他一個附加的問題:
下面的聲明都是什麼意思?

const int a;
int const a;
const int *a;
int * const a;
int const * a const;

/******/
前兩個的作用是一樣,a是一個常整型數。第三個意味着a是一個指向常整型數的指針(也就是,整型數是不可修改的,但指針可以)。第四個意思a是一個指向整型數的常指針(也就是說,指針指向的整型數是可以修改的,但指針是不可修改的)。最後一個意味着a是一個指向常整型數的常指針(也就是說,指針指向的整型數是不可修改的,同時指針也是不可修改的)。如果應試者能正確回答這些問題,那麼他就給我留下了一個好印象。順帶提一句,也許你可能會問,即使不用關鍵字 const,也還是能很容易寫出功能正確的程序,那麼我爲什麼還要如此看重關鍵字const呢?我也如下的幾下理由:
1) 關鍵字const的作用是爲給讀你代碼的人傳達非常有用的信息,實際上,聲明一個參數爲常量是爲了告訴了用戶這個參數的應用目的。如果你曾花很多時間清理其它人留下的垃圾,你就會很快學會感謝這點多餘的信息。(當然,懂得用const的程序員很少會留下的垃圾讓別人來清理的。)
2) 通過給優化器一些附加的信息,使用關鍵字const也許能產生更緊湊的代碼。
3) 合理地使用關鍵字const可以使編譯器很自然地保護那些不希望被改變的參數,防止其被無意的代碼修改。簡而言之,這樣可以減少bug的出現。


Volatile

8. 關鍵字volatile有什麼含意?並給出三個不同的例子。
一個定義爲volatile的變量是說這變量可能會被意想不到地改變,這樣,編譯器就不會去假設這個變量的值了。精確地說就是,優化器在用到這個變量時必須每次都小心地重新讀取這個變量的值,而不是使用保存在寄存器裏的備份。下面是volatile變量的幾個例子:
1) 並行設備的硬件寄存器(如:狀態寄存器)
2) 一箇中斷服務子程序中會訪問到的非自動變量(Non-automatic variables)
3) 多線程應用中被幾個任務共享的變量

回答不出這個問題的人是不會被僱傭的。我認爲這是區分C程序員和嵌入式系統程序員的最基本的問題。搞嵌入式的傢伙們經常同硬件、中斷、RTOS等等打交道,所有這些都要求用到volatile變量。不懂得volatile的內容將會帶來災難。
假設被面試者正確地回答了這是問題(嗯,懷疑是否會是這樣),我將稍微深究一下,看一下這傢伙是不是直正懂得volatile完全的重要性。
1)一個參數既可以是const還可以是volatile嗎?解釋爲什麼。
2); 一個指針可以是volatile 嗎?解釋爲什麼。
3); 下面的函數有什麼錯誤:

int square(volatile int *ptr)
{
        return *ptr * *ptr;
}

下面是答案:
1)是的。一個例子是隻讀的狀態寄存器。它是volatile因爲它可能被意想不到地改變。它是const因爲程序不應該試圖去修改它。
2); 是的。儘管這並不很常見。一個例子是當一箇中服務子程序修該一個指向一個buffer的指針時。
3) 這段代碼有點變態。這段代碼的目的是用來返指針*ptr指向值的平方,但是,由於*ptr指向一個volatile型參數,編譯器將產生類似下面的代碼:

int square(volatile int *ptr) 
{
    int a,b;
    a = *ptr;
    b = *ptr;
    return a * b;
}

由於*ptr的值可能被意想不到地該變,因此a和b可能是不同的。結果,這段代碼可能返不是你所期望的平方值!正確的代碼如下:

long square(volatile int *ptr) 
{
    int a;
    a = *ptr;
    return a * a;
}

位操作(Bit manipulation)

9. 嵌入式系統總是要用戶對變量或寄存器進行位操作。給定一個整型變量a,寫兩段代碼,第一個設置a的bit 3,第二個清除a 的bit 3。在以上兩個操作中,要保持其它位不變。
對這個問題有三種基本的反應
1)不知道如何下手。該被面者從沒做過任何嵌入式系統的工作。
2) 用bit fields。Bit fields是被扔到C語言死角的東西,它保證你的代碼在不同編譯器之間是不可移植的,同時也保證了的你的代碼是不可重用的。我最近不幸看到 Infineon爲其較複雜的通信芯片寫的驅動程序,它用到了bit fields因此完全對我無用,因爲我的編譯器用其它的方式來實現bit fields的。從道德講:永遠不要讓一個非嵌入式的傢伙粘實際硬件的邊。
3) 用 #defines 和 bit masks 操作。這是一個有極高可移植性的方法,是應該被用到的方法。最佳的解決方案如下:

#define BIT3 (0x1 << 3)
static int a;

void set_bit3(void) 
{
    a |= BIT3;
}
void clear_bit3(void) 
{
    a &= ~BIT3;
}

一些人喜歡爲設置和清除值而定義一個掩碼同時定義一些說明常數,這也是可以接受的。我希望看到幾個要點:說明常數、|=和&=~操作。


訪問固定的內存位置(Accessing fixed memory locations)

10. 嵌入式系統經常具有要求程序員去訪問某特定的內存位置的特點。在某工程中,要求設置一絕對地址爲0x67a9的整型變量的值爲0xaa66。編譯器是一個純粹的ANSI編譯器。寫代碼去完成這一任務。
這一問題測試你是否知道爲了訪問一絕對地址把一個整型數強制轉換(typecast)爲一指針是合法的。這一問題的實現方式隨着個人風格不同而不同。典型的類似代碼如下:
    int *ptr;
    ptr = (int *)0x67a9;
    *ptr = 0xaa55;

A more obscure approach is: 
一個較晦澀的方法是:

    *(int * const)(0x67a9) = 0xaa55;

即使你的品味更接近第二種方案,但我建議你在面試時使用第一種方案。

中斷(Interrupts)

11. 中斷是嵌入式系統中重要的組成部分,這導致了很多編譯開發商提供一種擴展—讓標準C支持中斷。具代表事實是,產生了一個新的關鍵字 __interrupt。下面的代碼就使用了__interrupt關鍵字去定義了一箇中斷服務子程序(ISR),請評論一下這段代碼的。

__interrupt double compute_area (double radius) 
{
    double area = PI * radius * radius;
    printf("\nArea = %f", area);
    return area;
}

這個函數有太多的錯誤了,以至讓人不知從何說起了:
1)ISR 不能返回一個值。如果你不懂這個,那麼你不會被僱用的。
2) ISR 不能傳遞參數。如果你沒有看到這一點,你被僱用的機會等同第一項。
3) 在許多的處理器/編譯器中,浮點一般都是不可重入的。有些處理器/編譯器需要讓額處的寄存器入棧,有些處理器/編譯器就是不允許在ISR中做浮點運算。此外,ISR應該是短而有效率的,在ISR中做浮點運算是不明智的。
4) 與第三點一脈相承,printf()經常有重入和性能上的問題。如果你丟掉了第三和第四點,我不會太爲難你的。不用說,如果你能得到後兩點,那麼你的被僱用前景越來越光明瞭。


代碼例子(Code examples)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章