1.C語言中,修飾符volatile的含義是什麼?舉例說明其使用場合。
答.volatile提醒編譯起它後面所定義的變量隨時都有可能發生改變,因此編譯後的程序每次需要存儲或讀取這個變量的時候,都會直
接從變量地址中讀取數據。如果沒有volatile關鍵字,則編譯器可能優化讀取和存儲,可能暫時使用寄存器中的值,如果這個變化由別
的程序更新了的話,將會出現不一致現象。
一般來說,volatile用在如下幾個地方:
(1)中斷服務程序中修改的供其他程序檢測的變量需要加volatile;
(2)多任務環境下各任務間共享的標誌因該加volatile;
(3)存儲器映射的硬件寄存器通常也要加volatile,因爲每次對它的讀寫都可能有不同意義。
2.請問TCP/IP協議分爲哪幾層?FTP協議屬於哪一層?
答.
(1)應用層:應用程序間溝通的層,如簡單電子郵件傳輸(SMTP)、文件傳輸協議(FTP,file transfer protocol)、網絡遠程訪問協
議(Telnet)等。
(2)傳輸層:在此層中,它提供了節點間的數據傳送服務,如傳輸控制協議(TCP)、用戶數據報協議(UDP,user datagram protocol
)等,TCP和UDP給數據包加入傳輸數據並把它傳輸到下一層中,這一層負責傳送數據,並且確定數據已被送達並接收。
(3)互連網絡層:負責提供基本的數據封包傳送功能,讓每一塊數據包都能夠到達目的主機(但不檢查是否被正確接收),如網際協議
(IP)。
(4)網絡接口層:對實際的網絡媒體的管理,定義如何使用實際網絡(如Ethernet、Serial Line等)來傳送數據。
補充:ISO的七層模型:應用層,表示層,會話層,傳輸層,網絡層,物理鏈路層,物理層
TCP 服務提供了數據流傳輸、可靠性、有效流控制、全雙工操作和多路複用技術等。
與 TCP 不同, UDP 並不提供對 IP 協議的可靠機制、流控制以及錯誤恢復功能等。由於 UDP 比較簡單, UDP 頭包含很少的字節,
比 TCP 負載消耗少。
tcp: 提供穩定的傳輸服務,有流量控制,缺點是包頭大,冗餘性不好
udp: 不提供穩定的服務,包頭小,開銷小
3.什麼是預編譯 何時需要預編譯?
答.
預編譯又稱爲預處理,是做些代碼文本的替換工作。處理#開頭的指令,比如拷貝#include包含的文件代碼,#define宏定義的替換,
條件編譯等。就是爲編譯做預備工作的階段,主要處理#開始的預編譯指令,預編譯指令指示了在程序正式編譯前就由編譯起進行的操作
,可以放在程序中的任何位置。預處理功能主要有三種:1)宏定義 2)文件包含 3)條件編譯
4.c和c++中的struct有什麼不同?
c和c++中struct的主要區別是c中的struct不可以含有成員函數,而c++中的struct可以。c++中struct和class的主要區別在於默認的
存取權限不同,struct默認爲public,而class默認爲private。
5.main函數的返回值:mian中,c標準認爲0表示成功,非0表示錯誤。具體的值是某中具體出錯信息
6.要對絕對地址0x100000賦值,我們可以用(unsigned int*)0x100000 = 1234;那麼要是想讓程序跳轉到絕對地址是0x100000去執行,應
該怎麼做?
*((void (*)( ))0x100000 ) ( );
首先要將0x100000強制轉換成函數指針,即:
(void (*)())0x100000
然後再調用它:
*((void (*)())0x100000)();
用typedef可以看得更直觀些:
typedef void(*)() voidFuncPtr;
*((voidFuncPtr)0x100000)();
7.線程與進程的區別和聯繫? 線程是否具有相同的堆棧?
進程是死的,只是一些資源的集合,真正的程序執行都是線程來完成的,程序啓動的時候操作系統就幫你創建了一個主線程。
每個線程有自己的堆棧。
8.分析下面的程序:
void GetMemory(char **p,int num)
{
*p=(char *)malloc(num);
}
int main()
{
char *str=NULL;
GetMemory(&str,100);
strcpy(str,"hello");
free(str);
if(str!=NULL)
{
strcpy(str,"world");
}
printf("\n str is %s",str); 軟件開發網 www.mscto.com
getchar();
}
問輸出結果是什麼?
輸出str is world。
free 只是釋放的str指向的內存空間,它本身的值還是存在的.所以free之後,有一個好的習慣就是將str=NULL.
此時str指向空間的內存已被回收,如果輸出語句之前還存在分配空間的操作的話,這段存儲空間是可能被重新分配給其他變量的,
儘管這段程序確實是存在大大的問題(上面各位已經說得很清楚了),但是通常會打印出world來。
這是因爲,進程中的內存管理一般不是由操作系統完成的,而是由庫函數自己完成的。
當你malloc一塊內存的時候,管理庫向操作系統申請一塊空間(可能會比你申請的大一些),然後在這塊空間中記錄一些管理信息
(一般是在你申請的內存前面一點),並將可用內存的地址返回。但是釋放內存的時候,管理庫通常都不會將內存還給操作系統,因此
你是可以繼續訪問這塊地址的。
9.用預處理指令#define 聲明一個常數,用以表明1 年中有多少秒
意識到這個表達式將使一個16 位機的整型數溢出-因此要用到長整型符號L,告訴編譯器這個常數是的長整型數。
如果你在你的表達式中用到UL(表示無符號長整型),那麼你有了一個好的起點。記住,第一印象很重要
#define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL
10.嵌入式系統經常具有要求程序員去訪問某特定的內存位置的特點。在某工程中,要求設置一絕對地址爲0x67a9 的整型變量的值爲
0xaa66。編譯器是一個純粹的ANSI 編譯器。寫代碼去完成這一任務。
這一問題測試你是否知道爲了訪問一絕對地址把一個整型數強制轉換(typecast)爲一指針是合法的。這一問題的實現方式
隨着個人風格不同而不同。典型的類似代碼如下:
int *ptr;
ptr = (int *)0x67a9;
*ptr = 0xaa55;
11.若寄存器的地址爲ox53000000,如何定義一個宏訪問它的值?
#define rWTCON (*(volatile unsigned *)0x53000000)
12.下面的代碼輸出是什麼,爲什麼?
void foo(void)
{
unsigned int a = 6;
int b = -20;
(a+b > 6) ? puts("> 6") : puts("<= 6");
}
這個問題測試你是否懂得C 語言中的整數自動轉換原則,我發現有些開發者懂得極少這些東西。不管如何,這無符號整型問題的答案是
輸出是 ">6"。原因是當表達式中存在有符號類型和無符號類型時所有的操作數都自動轉換爲無符號類型。因此-20 變成了一個非常大的
正整數,所以該表達式計算出的結果大於6。這一點對於應當頻繁用到無符號數據類型的嵌入式系統來說是豐常重要的。
13.define和typedef
(1)關鍵字typedef在編譯階段有效,由於是在編譯階段,因此typedef有類型檢查的功能。
Define則是宏定義,發生在預處理階段,也就是編譯之前,它只進行簡單而機械的字符串替換,而不進行任何檢查。
(2)Typedef用來定義類型的別名
(3)#define沒有作用域的限制,只要是之前預定義過的宏,在以後的程序中都可以使用。而typedef有自己的作用域。
14.浮點型變量並不精確,所以不可將float 變量用“==”或“!=”與數字比較,應該設法轉化成“>=”
或“<=”形式。如果寫成if (x == 0.0),則判爲錯。if ((x >= - EPSINON) && (x <= EPSINON)
15.assert宏的原型定義在<assert.h>中,其作用是如果它的條件返回錯誤,則終止程序執行,原型定義:
#include <assert.h>
void assert( int expression );
16.程序:
char *GetMemory( void )
{
char p[] = "hello world";
return p;
}
void Test( void )
{
char *str = NULL;
str = GetMemory();
printf( str );
}
char p[] = "hello world";
return p;
的p[]數組爲函數內的局部自動變量,在函數返回後,內存已經被釋放。這是許多程序員常犯的錯誤,
其根源在於不理解變量的生存期
17.求二進制數中1的個數
快速法:
int BitCount2(unsigned int n)
{
unsigned int c =0 ;
for (c =0; n; ++c)
{
n &= (n -1) ; // 清除最低位的1
}
return c ;
}
查表法:
int BitCount3(unsigned int n)
{
// 建表
unsigned char BitsSetTable256[256] = {0} ;
// 初始化表
for (int i =0; i <256; i++)
{
BitsSetTable256[i] = (i &1) + BitsSetTable256[i /2];
}
unsigned int c =0 ;
// 查表
unsigned char* p = (unsigned char*) &n ;
c = BitsSetTable256[p[0]] +
BitsSetTable256[p[1]] +
BitsSetTable256[p[2]] +
BitsSetTable256[p[3]];
return c ;
}