|
【第一部分 C基本概念】 【幾個(gè)關(guān)鍵字】 1)、auto關(guān)鍵字: 聲明變量的生存期為自動(dòng),即將不在任何類、結(jié)構(gòu)、枚舉、聯(lián)合和函數(shù)中定義的變量視為全局變量,而在函數(shù)中定義的變量視為局部變量。不明白?無視他好了,編譯器默認(rèn)的缺省情況下,所有的變量都是auto的。 2)、extern關(guān)鍵字: 我們都知道,一個(gè)變量或函數(shù),可以在a.c文件中定義,而在b.c文件中使用,這個(gè)時(shí)候,b.c就需要使用extern關(guān)鍵字來聲明這個(gè)變量和函數(shù),目的是為了告訴編譯器,這個(gè)函數(shù)在b.c之外,別讓我編譯不過! 3)、register關(guān)鍵字: 這個(gè)關(guān)鍵字就很少用到了,但是卻十分有用。它的目的是告訴編譯器盡量把這個(gè)變量放到寄存器中,這樣提高存取速度,但是不是能真的放到寄存器中卻不一定,畢竟寄存器的數(shù)量是有限的。在我們的二進(jìn)制翻譯器中,這個(gè)關(guān)鍵字被巧妙的用于線程切換。 4)、static關(guān)鍵字: 好吧,我承認(rèn)我土了,我就是栽在這個(gè)關(guān)鍵字上的。static有兩種修飾,分別如下: (1)修飾變量:變量分為全局變量和靜態(tài)變量,都存儲在內(nèi)存的靜態(tài)區(qū)中。 首先,當(dāng)static修飾全局變量的時(shí)候,該變量的作用域僅被限定在當(dāng)前文件中,別的文件即使使用extern關(guān)鍵字也無法使用這個(gè)變量。 其次,當(dāng)static修飾局部變量的時(shí)候,該變量在哪個(gè)函數(shù)體中定義,就只能在哪個(gè)函數(shù)體中使用。也許你會說,這不跟普通局部變量一樣么?不一樣!別忘了他是被存儲在內(nèi)存的靜態(tài)區(qū)中,所謂的靜態(tài)區(qū)就是全局區(qū),用來存放全局變量和靜態(tài)變量的,程序不結(jié)束,這個(gè)區(qū)是不會被釋放的,所以即使定義靜態(tài)局部變量的函數(shù)結(jié)束,改靜態(tài)局部變量仍然存在,下次訪問改函數(shù)的時(shí)候,這個(gè)變量的值仍然是上次的值! (2)修飾函數(shù): 經(jīng)常見這種形式,但沒怎么用過,也就沒去想。其實(shí)這個(gè)作用跟靜態(tài)全局變量相似,也是限定函數(shù)的作用域?yàn)楸疚募?。這樣作的好處就是不用操心是否會跟別人編寫的文件里的函數(shù)重名。 (3)注意:函數(shù)的形參不能聲明為靜態(tài),因?yàn)閷?shí)參總是在堆棧中傳遞給函數(shù),用于支持遞歸。 在《c和指針》中這樣描述:當(dāng)static用于函數(shù)定義時(shí),或用于代碼之外的變量聲明時(shí),static關(guān)鍵字用于修改標(biāo)識符的鏈接屬性,從external改為internal,但標(biāo)識符的存儲類型和作用域不受影響。用這種方式聲明的函數(shù)或變量只能在聲明它們的源文件中訪問。 當(dāng)static用于代碼塊內(nèi)部的變量聲明時(shí),static關(guān)鍵字用于修改變量的存儲類 型,從自動(dòng)變量修改為靜態(tài)變量,但變量的鏈接屬性和作用域不受影響。用這種方式聲明的變量在程序執(zhí)行之前創(chuàng)建,并在程序的整個(gè)執(zhí)行期間一直存在,而不是每 次在代碼塊開始執(zhí)行時(shí)創(chuàng)建,在代碼塊執(zhí)行完畢后銷毀。 5)、const關(guān)鍵字: 這是一個(gè)很有意思的關(guān)鍵字,他修飾的變量是只讀的,不能被修改;很多時(shí)候,編譯器會將其優(yōu)化成一個(gè)常量。const經(jīng)常被用來修飾函數(shù)的參數(shù),表示不希望這個(gè)參數(shù)值被函數(shù)體內(nèi)的代碼意外的改變。其實(shí),最有意思的是用const修飾一個(gè)指針,讓我們看下面這個(gè)例子:
這些各表示什么呢?注釋里面給出了答案!是不是很不好記?我們只需要記得,const修飾的是*p的時(shí)候,p指向的內(nèi)容不可變;const修飾的是p的時(shí)候,p就不可變!
6). sizeof關(guān)鍵字:很多人也許會大吃一斤,我類個(gè)去,sizeof居然是關(guān)鍵字?(高手請無視這里,我當(dāng)初就是這種表現(xiàn))。不錯(cuò),sizeof確實(shí)是關(guān)鍵字,而不是庫函數(shù)!所以,如果編譯時(shí)得不到一個(gè)數(shù)組的大小,那么就不能使用sizeof關(guān)鍵字來獲取改數(shù)組的大小! 7). typedef關(guān)鍵字: typedef說白了就是給一個(gè)已知的類型起一個(gè)外號。 8). volatile關(guān)鍵字: 也許你見過這個(gè)關(guān)鍵字,但一般你都沒有用過。哈哈,我用過!這個(gè)關(guān)鍵字表示改變量的值可能在外部被改變,編譯器在用到這個(gè)變量時(shí)不能過度的優(yōu)化,必須每次都重新從內(nèi)存中讀取這個(gè)變量的值,而不是將其優(yōu)化在寄存器中。 【鏈接】:c定義了三類鏈接:外部鏈接,內(nèi)部鏈接和無鏈接。 通常,函數(shù)和全局變量具有外部鏈接,這意味著它們對構(gòu)成程序的所有文件是可用的。 聲明為static的文件域?qū)ο缶哂袃?nèi)部鏈接,僅在聲明它們的文件中是已知的。 局部變量沒有鏈接,因此僅在他們自己的塊中是已知的。 【對齊】: 使用偽指令#pragma pack (n),C編譯器將按照n個(gè)字節(jié)對齊。 __attribute((aligned (n))),讓所作用的結(jié)構(gòu)成員對齊在n字節(jié)自然邊界上。如果結(jié)構(gòu)中有成員的長度大于n,則按照最大成員的長度來對齊。 【Standard linux memory layout】 【變量的值】:就是分配給該變量的內(nèi)存位置所存儲的數(shù)值,即使指針也不例外。 【inline函數(shù)和用macro定義的函數(shù)區(qū)別】 Macro定義
【匯編基礎(chǔ)】 ebp和esp是32位的SP,BP
EIP寄存器里存儲的是CPU下次要執(zhí)行的指令的地址。
附:Linux下使用objdump –S obj可以反匯編 【第二部分 Linux基礎(chǔ)】 【編譯過程】通常在使用gcc編譯程序時(shí),編譯過程通常會分為4個(gè)階段,即預(yù)處理,編譯,匯編和鏈接。 【僵尸進(jìn)程】如果某個(gè)進(jìn)程自身終止了,在調(diào)用exit清理完相關(guān)的內(nèi)容文件等資源后,它就會進(jìn)入ZOMBIE狀態(tài) 【孤兒進(jìn)程】當(dāng)某個(gè)進(jìn)程還在運(yùn)行時(shí),它的父進(jìn)程卻退出了,這個(gè)進(jìn)程卻沒有成為孤兒進(jìn)程 【fork兩次產(chǎn)生守護(hù)進(jìn)程】父進(jìn)程先fork出一個(gè)兒子進(jìn)程,兒子進(jìn)程再fork出孫子進(jìn)程做為守護(hù)進(jìn)程,然后兒子進(jìn)程立刻退出,守護(hù)進(jìn)程被init進(jìn)程接管,這樣無論父進(jìn)程做什么事,無論怎么被阻塞,都與守護(hù)進(jìn)程無關(guān)了。所以,fork兩次的守護(hù)進(jìn)程很安全,避免了僵尸進(jìn)程出現(xiàn)的可能性。 【內(nèi)核:各種地址】CPU將一個(gè)虛擬內(nèi)存空間中的地址轉(zhuǎn)換為物理地址,需要進(jìn)行兩步:首先將給定一個(gè)邏輯地址(其實(shí)是段內(nèi)偏移量,這個(gè)一定要理解?。。。?,CPU要利用其段式內(nèi)存管理單元,先將為個(gè)邏輯地址轉(zhuǎn)換成一個(gè)線程地址,再利用其頁式內(nèi)存管理單元,轉(zhuǎn)換為最終物理地址。 【inline】 通過在函數(shù)聲明的前面加上inline,即可告訴編譯程序優(yōu)化對函數(shù)的調(diào)用。從技術(shù)上講,這意味著函數(shù)的代碼將被有序擴(kuò)展而不是調(diào)用。當(dāng)然,inline只是對編譯程序的一個(gè)請求,可以忽略。注意,c++也支持inline說明符。 【Linux內(nèi)存分配類型】 系統(tǒng)為進(jìn)程分配數(shù)據(jù)空間有三種形式。 靜態(tài)分配 整塊靜態(tài)分配空間,包括其中的所有數(shù)據(jù)實(shí)體,都是在進(jìn)程創(chuàng)建時(shí)由系統(tǒng)一次性分配的(同時(shí)為UNIX稱為Text的代碼分配空間)。這塊空間在進(jìn)程運(yùn)行期間保持不變。 初始化的和未初始化的實(shí)體分別放在初始化數(shù)據(jù)段和未初始化數(shù)據(jù)段(BSS)。后者和前者不同,在.o文件a.out文件里都不存在(只有構(gòu)架信息),在進(jìn)程的虛擬空間里才展開。 extern變量和static變量采用靜態(tài)分配。 在進(jìn)程創(chuàng)建時(shí)做靜態(tài)分配,分配正文(text)段、數(shù)據(jù)段和棧空間。 正文和初始化數(shù)據(jù)是按a.out照樣復(fù)制過來;未初始化數(shù)據(jù)按構(gòu)架信息展開,填以0或空;??臻g的大小由鏈接器開關(guān)(具體哪個(gè)開關(guān)忘了)決定。 棧分配 整個(gè)??臻g已在進(jìn)程創(chuàng)建時(shí)分配好。棧指針SP的初值的設(shè)定,確定了??臻g的大小。鏈接器的某個(gè)開關(guān)可以設(shè)定??臻g的大小。在進(jìn)程運(yùn)行期間,棧空間的大小不變。但是,在進(jìn)程剛啟動(dòng)時(shí),??臻g是空的,里面沒有實(shí)體。在進(jìn)程運(yùn)行期間,對具體實(shí)體的棧分配是進(jìn)程自行生成(壓棧)和釋放(彈出)實(shí)體,系統(tǒng)并不參與。 auto變量和函數(shù)參數(shù)采用棧分配。 只要壓入的實(shí)體的總長度不超過棧空間尺寸,棧分配就與系統(tǒng)無關(guān)。如果超過了,就會引發(fā)棧溢出錯(cuò)誤。 堆分配 當(dāng)進(jìn)程需要生成實(shí)體時(shí),向系統(tǒng)申請分配空間;不再需要該實(shí)體時(shí),可以向系統(tǒng)申請回收這塊空間。 堆分配使用特定的函數(shù)(如malloc()等)或操作符(new)。所生成的實(shí)體都是匿名的,只能通過指針去訪問。 對實(shí)體來說,棧分配和堆分配都是動(dòng)態(tài)分配:實(shí)體都是在進(jìn)程運(yùn)行中生成和消失。而靜態(tài)分配的所有實(shí)體都是在進(jìn)程創(chuàng)建時(shí)全部分配好的,在運(yùn)行中一直存在。 同為動(dòng)態(tài)分配,棧分配與堆分配是很不相同的。前者是在進(jìn)程創(chuàng)建時(shí)由系統(tǒng)分配整塊棧空 間,以后實(shí)體通過壓棧的方式產(chǎn)生,并通過彈出的方式取消。不管是否產(chǎn)生實(shí)體,產(chǎn)生多少實(shí)體,??臻g總是保持原來的大小。后者并沒有預(yù)設(shè)的空間,當(dāng)需要產(chǎn)生 實(shí)體時(shí),才向系統(tǒng)申請正好能容納這個(gè)實(shí)體的空間。當(dāng)不再需要該實(shí)體時(shí),可以向系統(tǒng)申請回收這塊空間。因此,堆分配是真正的動(dòng)態(tài)分配。 顯然,堆分配的空間利用率最高。 棧分配和靜態(tài)分配也有共性:整塊空間是在進(jìn)程創(chuàng)建時(shí)由系統(tǒng)分配的。但是,后者同時(shí)分配了所有實(shí)體的空間,而前者在進(jìn)程啟動(dòng)時(shí)是空的。另外,棧上的實(shí)體和數(shù)據(jù)段里的實(shí)體都是有名實(shí)體,可以通過標(biāo)識符來訪問。
棧溢出的后果是比較嚴(yán)重的,或者出現(xiàn)Segmentation fault錯(cuò)誤,或者出現(xiàn)莫名其妙的錯(cuò)誤。 【Linux大小端問題】 所謂的大端模式,是指數(shù)據(jù)的低位(就是權(quán)值較小的后面那幾位)保存在內(nèi)存的高地址中,而數(shù)據(jù)的高位,保存在內(nèi)存的低地址中,這樣的存儲模式有點(diǎn)兒類似于把數(shù)據(jù)當(dāng)作字符串順序處理:地址由小向大增加,而數(shù)據(jù)從高位往低位放; 所謂的小端模式,是指數(shù)據(jù)的低位保存在內(nèi)存的低地址中,而數(shù)據(jù)的高位保存在內(nèi)存的高地址中,這種存儲模式將地址的高低和數(shù)據(jù)位權(quán)有效地結(jié)合起來,高地址部分權(quán)值高,低地址部分權(quán)值低,和我們的邏輯方法一致。 【自旋鎖、互斥量】 自旋鎖是一種非阻塞鎖,也就是說,如果某線程需要獲取自旋鎖,但該鎖已經(jīng)被其他線程占用時(shí),該線程不會被掛起,而是在不斷的消耗CPU的時(shí)間,不停的試圖獲取自旋鎖。 互斥量是阻塞鎖,當(dāng)某線程無法獲取互斥量時(shí),該線程會被直接掛起,該線程不再消耗CPU時(shí)間,當(dāng)其他線程釋放互斥量后,操作系統(tǒng)會激活那個(gè)被掛起的線程,讓其投入運(yùn)行。 【uboot】 Boot Loader 的 stage1 通常包括以下步驟(以執(zhí)行的先后順序): 1. 硬件設(shè)備初始化(關(guān)看門狗,關(guān)中斷,設(shè)置cpu時(shí)鐘,初始化sdram,關(guān)閉 CPU 內(nèi)部指令/數(shù)據(jù) cache)。 2. 為加載 Boot Loader 的 stage2 準(zhǔn)備 RAM 空間。 3. 拷貝 Boot Loader 的 stage2 到 RAM 空間中。 4. 設(shè)置好堆棧。 5. 跳轉(zhuǎn)到 stage2 的 C 入口點(diǎn)。 Boot Loader 的 stage2 通常包括以下步驟(以執(zhí)行的先后順序): 1. 初始化本階段要使用到的硬件設(shè)備。 2. 檢測系統(tǒng)內(nèi)存映射(memory map)。 3. 將 kernel 映像和根文件系統(tǒng)映像從 flash 上讀到 RAM 空間中。 4. 為內(nèi)核設(shè)置啟動(dòng)參數(shù)。 5. 調(diào)用內(nèi)核。 【第三部分 Linux內(nèi)核和驅(qū)動(dòng)】 【sofitirq,tasklet和workqueue】 中斷處理分為兩個(gè)部分:上半部和下半部。中斷處理程序?qū)儆谏习氩?,這三者屬于下半部分,下半部的任務(wù)就是執(zhí)行與中斷處理程序密切相關(guān)但中斷處理程序本身不執(zhí)行,推后執(zhí)行的工作。
1)軟中斷代碼最為簡潔,執(zhí)行效率也最快,但相同類型的軟中斷可以同時(shí)執(zhí)行(包擴(kuò)自己 “同時(shí)”是指同一時(shí)刻在多個(gè)cpu上執(zhí)行)這樣一來它提供的執(zhí)行序列化保障也就最少,意味著在軟中斷中必須對同享數(shù)據(jù)進(jìn)行加鎖,而且軟中斷不同于進(jìn)程,不能重新調(diào)度,這樣任何潛在睡眠的代碼不能出現(xiàn)在軟中斷中。 【likely and unlikely】 定義形式:
作用: unlikely指示gcc編譯器這種情況很少發(fā)生,在編譯優(yōu)化的時(shí)候分支預(yù)測會跳到else情況中。 likely指示這種情況發(fā)生的多,分支預(yù)測按照下面的語句走。 事實(shí)上,根據(jù)這兩個(gè)函數(shù)可以得知條件語句中最可能發(fā)生的情形,從而告知編譯器以允許它正確地優(yōu)化條件分支。
【skb_clone and skb_copy】 skb_copy是對skb的數(shù)據(jù)完整復(fù)制,也可以說是深拷貝。 skb_clone并沒有真正申請數(shù)據(jù)段,只是申請了一個(gè)skb_struct,并讓其指針指向原skb的數(shù)據(jù)段。 對比skb_copy和skb_clone,前者是一個(gè)深拷貝,而后者只是一個(gè)淺拷貝。
【kmalloc and vmalloc,malloc】 1. kmalloc和vmalloc是分配的是內(nèi)核的內(nèi)存,malloc分配的是用戶的內(nèi)存 2. kmalloc與malloc 相似,該函數(shù)返回速度快快(除非它阻塞)并對其分配的內(nèi)存不進(jìn)行初始化(清零),分配的區(qū)仍然持有它原來的內(nèi)容,分配的區(qū)也是在物理內(nèi)存中連續(xù)。kmalloc 能夠分配的內(nèi)存塊的大小有一個(gè)上限。kmalloc分配內(nèi)存是基于slab,因此slab的一些特性包括著色,對齊等都具備,性能較好。物理地址和邏輯地址都是連續(xù)的。 原型:void *kmalloc(size_t size, int flags); ———————————————————————————————- 3. vmalloc分配內(nèi)存的時(shí)候邏輯地址是連續(xù)的,但物理地址一般是不連續(xù)的,適用于那種一下需要分配大量內(nèi)存的情況,如insert模塊的時(shí)候。這種分配方式性能不如kmalloc。 4. kmalloc能分配的大小有限,vmalloc和malloc能分配的大小相對較大 5. 內(nèi)存只有在要被DMA訪問的時(shí)候才需要物理上連續(xù)
【OFFSET_OF(type,member) SIZE_OF】
宏功能:從結(jié)構(gòu)體(type)某成員變量(member)指針(ptr)來求出該結(jié)構(gòu)體(type)的首指針。 1、typeof( ( (type *)0)->member )為取出member成員的變量類型。 2、定義__mptr指針ptr為指向該成員變量的指針 3、mptr為member數(shù)據(jù)類型的常量指針,其指向ptr所指向的變量處 4、.(char *)__mptr轉(zhuǎn)換為字節(jié)型指針。(char *)__mptr -
offsetof(type,member))用來求出結(jié)構(gòu)體起始地址(為char *型指針),然后(type *)( (char *)__mptr
-offsetof(type,member) )在(type *)作用下進(jìn)行將字節(jié)型的結(jié)構(gòu)體起始指針轉(zhuǎn)換為type *型的結(jié)構(gòu)體起始指針。 【自旋鎖如何保護(hù)critical region】 自旋鎖可以確保在同時(shí)只有一個(gè)線程進(jìn)入臨界區(qū)。其他想進(jìn)入臨界區(qū)的線程必須不停地原地打轉(zhuǎn),直到第1個(gè)線程釋放自旋鎖。注意:這里所說的線程不是內(nèi)核線程,而是執(zhí)行的線程。 【互斥體】 與自旋鎖不同的是,互斥體在進(jìn)入一個(gè)被占用的臨界區(qū)之前不會原地打轉(zhuǎn),而是使當(dāng)前線程進(jìn)入睡眠狀態(tài)。如果要等待的時(shí)間較長,互斥體比自旋鎖更合適,因?yàn)樽孕i會消耗CPU資源。在使用互斥體的場合,多于2次進(jìn)程切換時(shí)間都可被認(rèn)為是長時(shí)間,因此一個(gè)互斥體會引起本線程睡眠,而當(dāng)其被喚醒時(shí),它需要被切換回來。 因此,在很多情況下,決定使用自旋鎖還是互斥體相對來說很容易: (1) 如果臨界區(qū)需要睡眠,只能使用互斥體,因?yàn)樵讷@得自旋鎖后進(jìn)行調(diào)度、搶占以及在等待隊(duì)列上睡眠都是非法的; (2) 由于互斥體會在面臨競爭的情況下將當(dāng)前線程置于睡眠狀態(tài),因此,在中斷處理函數(shù)中,只能使用自旋鎖。 [ISR即中斷服務(wù)程序中可以調(diào)用printk函數(shù)嗎?] 盡量不要使用,printk可能會引起睡眠。而中斷處理程序是不允許睡眠的! 【下面的代碼就使用了__interrupt關(guān)鍵字去定義了一個(gè)中斷服務(wù)子程序(ISR),請?jiān)u論一下這段代碼的。】
這個(gè)函數(shù)有太多的錯(cuò)誤了,以至讓人不知從何說起了:
【第四部分編程】 【指針】
【變元函數(shù)】func(…)/*illegal*/ 【c和c++函數(shù)原型聲明】 在c和c++處理函數(shù)原型的方式上,存在著細(xì)小但重要的差別,C++的函數(shù)原型沒有參數(shù)。在C++中,原型中不帶任何參數(shù)表示空參數(shù)表。 在C中,函數(shù)沒有參數(shù)時(shí),其原型使用參數(shù)表中的void。如,float f(void) ; 它告訴編譯程序該函數(shù)沒有參數(shù),且對沒有變元的函數(shù)的任何調(diào)用都將出錯(cuò)。 【向函數(shù)傳遞全結(jié)構(gòu)】 結(jié)構(gòu)用做函數(shù)的變元時(shí),用標(biāo)準(zhǔn)值調(diào)用規(guī)則把全結(jié)構(gòu)傳給函數(shù)。因此,函數(shù)對結(jié)構(gòu)內(nèi)容的修改不影響原結(jié)構(gòu),即退出函數(shù)后,原結(jié)構(gòu)內(nèi)容不變。同時(shí),當(dāng)執(zhí)行函數(shù)調(diào)用時(shí),向棧中壓入數(shù)據(jù)需要花費(fèi)開銷。 向函數(shù)傳結(jié)構(gòu)指針時(shí),壓棧的只是指針本身,使函數(shù)調(diào)用特別快;在有些情況下,傳遞指針的第二個(gè)優(yōu)點(diǎn)是,在傳遞指針時(shí),該函數(shù)可以修改作為變元的結(jié)構(gòu)的內(nèi)容。 【c和c++結(jié)構(gòu)聲明方法不同】 在C++中,一旦結(jié)構(gòu)已經(jīng)聲明,僅使用此結(jié)構(gòu)的標(biāo)記即可聲明此類變量,而不必在其前面加上關(guān)鍵字struct。造成這種差別的原因是,在C中,結(jié)構(gòu)名并未定義完整的類型名。這就是C語言將這個(gè)名字稱為標(biāo)記的原因。但在c++中,結(jié)構(gòu)名是完整的類型名,可以被自身用以定義變量。但請記住,在C++程序中使用c風(fēng)格的聲明始終是完全合法的。上述討論可以推 廣到聯(lián)合和枚舉。 【位域】C語言具有訪問字節(jié)中位的內(nèi)設(shè)機(jī)制。type name:length
說明data為bs變量,共占兩個(gè)字節(jié)。其中位域a占8位,位域b占2位,位域c占6位。對于位域的定義尚有以下幾點(diǎn)說明: 1. 一個(gè)位域必須存儲在同一個(gè)字節(jié)中,不能跨兩個(gè)字節(jié)。如一個(gè)字節(jié)所??臻g不夠存放另一位域時(shí),應(yīng)從下一單元起存放該位域。也可以有意使某位域從下一單元開始。 2. 由于位域不允許跨兩個(gè)字節(jié),因此位域的長度不能大于一個(gè)字節(jié)的長度,也就是說不能超過8位二進(jìn)位。 3. 位域可以無位域名,這時(shí)它只用來作填充或調(diào)整位置。無名的位域是不能使用的。
【sizeof】聯(lián)合的尺寸總是等于聯(lián)合中最大的成員的尺寸。 【char和unsigned char的區(qū)別】 char的值在-128~127之間, unsigned char的值在0~255之間 for example:
【右移一位等于除以2】右移一位就等于除以2,但是這里需要加一個(gè)條件,這里指的是正數(shù)。而對于有符號整數(shù),且其值為負(fù)數(shù)時(shí),在C99標(biāo)準(zhǔn)中對于其右移操作的結(jié)果的規(guī)定是implementation-defined. 【大小端程序?qū)崿F(xiàn)】
【一個(gè)二進(jìn)制數(shù)中含有的“1”的個(gè)數(shù)】
【實(shí)現(xiàn)memmove】
【find the nth to the last of single linked node
查找鏈表中倒數(shù)第k個(gè)結(jié)點(diǎn)】
方法一:求出正數(shù)第n-k+1個(gè)結(jié)點(diǎn)即可 代碼如下:
方法二:如果我們在遍歷時(shí)維持兩個(gè)指針,第一個(gè)指針從鏈表的頭指針開始遍歷,在第k-1步之前,第二個(gè)指針保持不動(dòng);在第k-1步開始,第二個(gè)指針也開始從鏈表的頭指針開始遍歷。由于兩個(gè)指針的距離保持在k-1,當(dāng)?shù)谝粋€(gè)(走在前面的)指針到達(dá)鏈表的尾結(jié)點(diǎn)時(shí),第二個(gè)指針(走在后面的)指針正好是倒數(shù)第k個(gè)結(jié)點(diǎn)。 這種思路只需要遍歷鏈表一次。對于很長的鏈表,只需要把每個(gè)結(jié)點(diǎn)從硬盤導(dǎo)入到內(nèi)存一次。因此這一方法的時(shí)間效率前面的方法要高。 代碼如下:
【單鏈表全】
【給定一個(gè)整型變量a,寫兩段代碼,第一個(gè)設(shè)置a的bit 3,第二個(gè)清除a 的bit 3。在以上兩個(gè)操作中,要保持其它位不變。】 【林銳getMemory】
【訪問固定的內(nèi)存位置】 在某工程中,要求設(shè)置一絕對地址為0x67a9的整型變量的值為0xaa66。編譯器是一個(gè)純粹的ANSI編譯器。寫代碼去完成這一任務(wù)。
【林銳高質(zhì)量c/c++編程習(xí)題(選)】
請問運(yùn)行Test函數(shù)會有什么樣的結(jié)果? 答:程序崩潰。因?yàn)?span style="font-family:Calibri">GetMemory并不能傳遞動(dòng)態(tài)內(nèi)存, Test函數(shù)中的 str一直都是 NULL。strcpy(str, "hello world");將使程序崩潰。
請問運(yùn)行Test函數(shù)會有什么樣的結(jié)果? 答:可能是亂碼。 因?yàn)镚etMemory返回的是指向“棧內(nèi)存”的指針,該指針的地址不是 NULL,但其原現(xiàn)的內(nèi)容已經(jīng)被清除,新內(nèi)容不可知。
請問運(yùn)行Test函數(shù)會有什么樣的結(jié)果? 答: (1)能夠輸出hello (2)內(nèi)存泄漏
請問運(yùn)行Test函數(shù)會有什么樣的結(jié)果? 答:篡改動(dòng)態(tài)內(nèi)存區(qū)的內(nèi)容,后果難以預(yù)料,非常危險(xiǎn)。 因?yàn)閒ree(str);之后str成為野指針, if(str != NULL)語句不起作用。
【排序算法(合集)】 插入排序 算法概要:插入排序依據(jù)遍歷到第N個(gè)元素的時(shí)候前面的N-1個(gè)元素已經(jīng)是排序好的,那么就查找前面的N-1個(gè)元素把這第N個(gè)元素放在合適的位置,如此下去直到遍歷完序列的元素為止。
希爾排序 算法概要:shell排序是對插入排序的一個(gè)改裝,它每次排序排序根據(jù)一個(gè)增量獲取一個(gè)序列,對這這個(gè)子序列進(jìn)行插入排序,然后不斷的縮小增量擴(kuò)大子序列的元素?cái)?shù)量,直到增量為1的時(shí)候子序列就和原先的待排列序列一樣了,此時(shí)只需要做少量的比較和移動(dòng)就可以完成對序列的排序了。
冒泡排序 算法概要:冒泡排序是經(jīng)過n-1趟子排序完成的,第i趟子排序從第1個(gè)數(shù)至第n-i個(gè)數(shù),若第i個(gè)數(shù)比后一個(gè)數(shù)大(則升序,小則降序)則交換兩數(shù)。
快速排序 快速排序(Quicksort)是對冒泡排序的一種改進(jìn)。通過一趟排序?qū)⒁判虻臄?shù)據(jù)分割成獨(dú)立的兩部分,其中一部分的所有數(shù)據(jù)都比另外一部分的所有數(shù)據(jù)都要小,然后再按此方法對這兩部分?jǐn)?shù)據(jù)分別進(jìn)行快速排序,整個(gè)排序過程可以遞歸進(jìn)行,以此達(dá)到整個(gè)數(shù)據(jù)變成有序序列。
歸并排序 算法概要:歸并排序法是將兩個(gè)(或兩個(gè)以上)有序表合并成一個(gè)新的有序表,即把待排序序列分為若干個(gè)子序列,每個(gè)子序列是有序的。然后再把有序子序列合并為整體有序序列。
【第五部分 WiFi】 WiFi. 12. ToDS From Ds
13. RTS CTS
|
|
|