6.2 筆試真題 & 詳解
真題 1:
1,ISR,APC,DPC 的定義。
2,Windows/ Linux 下系統創建進程的步驟。
3,xtoa 函數,輸入是兩個整數,原數字,數制,輸出是字符串。
4,實現內存拷貝的 C 函數。
5,比較兩個二叉樹結構是否一樣。
6,C++中 volatile 關鍵字的作用。
7,一個程序找錯誤。
8,根據上述錯誤給程序員發郵件提出改進意見。
9,最喜歡的一首唐詩,原因。
10,當代最崇拜的人,原因。
真題 2:
1、選擇下面哪一個是時序電路。四個選項分別是 ADD XOR Latch D-Flop。
2、問系統工作的最大時鐘頻率是否跟 Hold time 有關,并說明理由。
3、畫出下面兩個代碼綜合出來的電路圖,并說明原因。 a:if(aflag)
begin opt1 <= a; opt2 <= b; end esle begin opt1 <= c; opt2 <= d; end
always@(posedge clk)
out_data <= opt1 +opt2; b: if(aflag)
out_data <= a+b; else
out_data <= c+d;
4、用圖表說明下列腳本命令。
a: set_multicycle_path 4 -setup -from dffa/cp -to dffb/d b: set_multicycle_path 4 -setup -from dffa/cp -to dffb/d set_multicycle_path 4 -hold -from dffa/cp -to dffb/d
//這三個命令不一定完全正確,憑記憶大概是這個樣子的
5、5 分頻,用 Verilog HDL/VHDL 實現。
6、timescale 1ns/1ps 與`timescale 1ns/50ps 分別代表的意義以及區別。
7.分別用 shell 以及 perl(或任一你熟知的腳本語言)將當前目錄下所有".c"文件后綴改 成".cc"。
真題 3:
1:windows API 里面用于線程同步的有哪些?
答案:共有 12 個 API
1)、臨界區共有五個 API。
(1)InitializeCriticalSection
此函數用于設臵臨界區對象, 即對臨界區對象初始化。該函數必須在執行 EnterCriticalSection 前調用。單個進程的線程可以為互斥同步使用臨界區對象。進程負 責分配臨界區對象使用的內存,可以通過對 CRITICAL_SECTION 類型變量的定義和使用 來實現。
(2)EnterCriticalSection
此函數用于等待指定的臨界區對象的所有權。授予調用線程所有權后,該函數返回, 臨界區對象在單個進程的各線程內強制互斥同步。在線程擁有臨界區對象以后,對同一 個臨界區對象應調用
nterCriticalSection 函數,防止發生死鎖。在退出臨界區后用 LeaveCriticalSection 函數使其他線程可以進入臨界區。
(3)TryEnterCriticalSection
此函數用沒有阻塞的方式試圖進入一個臨界區。若函數調用成功,則進行調用的線 程擁有對臨界區的所有權,否則立即返回。
(4)LeaveCriticalSection
此函數用于釋放對臨 界區對象的所有權。 每次線程對同一個對象執行 EnterCriticalSection 或 TryEnterCriticalSection 都必須調用 LeaveCriticalSection 函數。
(5)DeleteCriticalSection 此函數用于刪除一個臨界區對象,釋放所有與不再為自己所控制的臨界區對象有關的資源。一個臨界區對象被刪除, 就不能再對其調用函數 EnterCriticalSection ,函數TryEnterCriticalSection 和函數 LeaveCriticalSection 了。
2)、互斥和信號量共有 7 個 API。
(1)CreateMutex
此函數用于創建命名或未命名的互斥對象。這些互斥對象用于進程同步,當互斥對 象不為任何線程擁有時才處于信號態,否則將處于非信號態。若要線程釋放其所有權, 則線程在每次互斥對象處于非信號態時都調用函數 ReleaseMutex。當不再需要互斥對象 時可以使用函數 CloseHandle 來關閉互斥對象。當所有互斥對象的打開句柄都關閉時, 就刪除互斥對象。
(2)OpenMutex
用于返回存在的已命名互斥對象的句柄。該函數允許多個進程打開同一個互斥對象 的句柄。該函數的調用一定要在函數 CreateMutex 創建互斥對象之后,當不需要句柄時 可以調用 CloseHandle 函數。
(3)ReleaseMutex
此函數用于釋放互斥對象。若函數調用成功,互斥對象處于信號態。 (4)CreateSemaphore 此函數用于創建已命名或未命名的信號量對象,信號量用計數器實現同步。每次取信號量時(可利用函數WaitForSingleObject 來取),信號量計數器遞減;每次ReleaseSemaphore 釋放信號量值時,信號量計數器遞增。計數永遠不會小于 0 或大 于在 lSemMaxCount 參數中定義的值。
(5)OpenSemaphore
用于打開一個已經存在的命名的信號量對象。該信號量必須是 CreateSemaphore 創 建的。如果不再需要時,可以用函數 CloseHandle 關閉返回的句柄。
(6)WaitForSingleObject
此函數僅當在參數列表中指定的對象處于信號態或超過了超時間隔時,該函數才返 回。
(7)ReleaseSemaphore
用來遞增信號量的計數。對于 CreateSemaphore 函數創建的對象使用,計數可以達 到設定的最大計數值。
2: windows 內核內存分為 paged memory 和 nonpaged memory,請問有什么區別? 答案:paged memory:是指可以分頁的內存,可以交換到硬盤文件上。Nonpaged memory:不可分頁,也就是不能交換到硬盤文件上。有些內存,比如驅動程序,內核代碼是不允許交換出去的,應該常駐內存,就使用 nonpaged memory。
3:請問什么情況下,cache 中只放指令(數據直接從存儲器存。┍ cache 中放數據和指令的效率高?
答案:計算密集型 cache 中只放指令(數據直接從存儲器存取)比 cache 中放數據 和指令的效率高,可以充分利用指令的局部原理。
4:RISC 和 CISC 等其他指令集相比有哪些優點,請至少舉出 5 個。
答案:(1)尋址方式少且簡單,一般為 2—3 種,最多不超過 4 種,絕不出現存儲器間接尋址方式。
(2)指令集中的指令數目一般少于 100 種,指令格式一般少于 4 種。
(3)指令功能簡單,控制器多采用硬布線方式,以期更快的執行速度。
(4)平均而言,所有指令的執行時間為一個處理時鐘周期。
(5)指令格式中用于指派整數寄存器的個數不少于 32 個,用于指派浮點數寄存器的個數不少于 16 個。
(6)強調通用寄存器資源的優化使用。
(7)支持指令流水并強調指令流水的優化使用。
5:選擇題:
如果兩個節點 x,y,preorder 遍歷,x 在 y 之前,postorder 遍歷,x 在y 之后,請問 x,y 的關系為:
A.x 是 y 的左兄弟。
B x 是 y 的右兄弟。
C.x 是 y 的祖先。 D x 是 y 的后裔。 答案:C。
6:請問下面程序如果運行會出現什么結果?如果有錯誤請指出并改正。
include <stdlib.h> include <string.h> class mystring{ public: mystring(){ m_str=NULL;
}
mystring(mystring& str){ if(m_str!=NULL){
delete []m_str;
}
m_str=new char[strlen(str.m_str)]; strcpy(m_str,str.m_str);
}
mystring & operator=(const char *str){ if(m_str!=NULL){
delete []m_str;
}
m_str=new char[strlen(str)+1]; strcpy(m_str,str);
}
~mystring(){ if(m_str!=NULL){ delete m_str;
}
}
private:
char *m_str;
};
int main(){ mystring str1; str1="hello world"; mystring str2; str2=str1;
mystring str3=str2;
return 0;
}
答案:程序運行會出現內存釋放錯誤,錯誤共有四處,分別在下面改正的代碼中標出。
include <stdlib.h> include <string.h>
class mystring{ public: mystring(){ m_str=NULL; } mystring(mystring& str){
/*if(m_str!=NULL){ delete []m_str; }*/
//錯誤 1,因為 m_str 沒有被初始化,所以此處可能為 NULL,也可能不為 NULL, 如 果 不 為 null , 則 會 出 錯 , 因 為 m_str 是 一 個 隨 機 的 值 。 m_str=new
char[strlen(str.m_str)+1];
//錯誤 2:長度應該+1 strcpy(m_str,str.m_str); }
mystring & operator=(mystring& str){
//錯誤 3 : 缺少賦值重載函數 if(m_str!=NULL){ delete []m_str; } m_str=new
har[strlen(str.m_str)+1];
//錯誤 2:長度應該+1 strcpy(m_str,str.m_str); } mystring & operator=(const char
*str){ if(m_str!=NULL){ delete []m_str; } m_str=new char[strlen(str)+1]; strcpy(m_str,str); }
~mystring(){ if(m_str!=NULL){ delete []m_str;
//錯誤 4:析構函數中,應該析構數組 } } private: char *m_str; }; int main(){ mystring str1;
str1="hello world"; mystring str2; str2=str1; mystring str3=str2; return 0; }。
7:100 個乒乓球取勝之道,A,B兩個人輪流拿,A先拿,一次只能拿[1,5]個, 獲勝者為拿到最后一個球的人。請問 A 第一次該拿幾個?以后又該怎么拿,才能夠確 保獲勝?
答案:A 先拿 4 個,然后 B 拿,設 B 拿 x 個,則每次 A 拿 6-x 個即可。
8:有編號 1-50 的人,依次排列,然后單號出列,然后剩下的人重新編號,單號 出列,依次類推,最后剩下一個人,請問這個人原來編號是多少號?如果是每一次雙號 出列,請問這個人原來編號是多少?
答案:單號出列:32 號,雙號出列:1 號。