[置顶] C/C++超级大火锅
寫(xiě)在前面
最近接觸到一些基礎(chǔ)知識(shí),平時(shí)遇到的編程困惑也加入其中。準(zhǔn)確說(shuō)是寫(xiě)給自己看的,但是如果大家可以借鑒就更好。多數(shù)是c/c++,也有少量Java基礎(chǔ)和其他知識(shí),貌似應(yīng)該叫《計(jì)算機(jī)基礎(chǔ)問(wèn)題匯總》比較好。不斷更新~~
一、new 跟 malloc 的區(qū)別是什么?
1.malloc/free是C/C++語(yǔ)言的標(biāo)準(zhǔn)庫(kù)函數(shù),new/delete是C++的運(yùn)算符
2.new能夠自動(dòng)分配空間大小
3.對(duì)于用戶自定義的對(duì)象而言,用maloc/free無(wú)法滿足動(dòng)態(tài)管理對(duì)象的要求。對(duì)象在創(chuàng)建的同時(shí)要自動(dòng)執(zhí)行構(gòu)造函數(shù),對(duì)象在消亡之前要自動(dòng)執(zhí)行析構(gòu)函數(shù)。由于malloc/free是庫(kù)函數(shù)而不是運(yùn)算符,不在編譯器控制權(quán)限之內(nèi),不能夠把執(zhí)行構(gòu)造函數(shù)和析構(gòu)函數(shù)的任務(wù)強(qiáng)加于malloc/free。因此C++需要一個(gè)能對(duì)對(duì)象完成動(dòng)態(tài)內(nèi)存分配和初始化工作的運(yùn)算符new,以及一個(gè)能對(duì)對(duì)象完成清理與釋放內(nèi)存工作的運(yùn)算符delete—簡(jiǎn)而言之 new/delete能進(jìn)行對(duì)對(duì)象進(jìn)行構(gòu)造和析構(gòu)函數(shù)的調(diào)用進(jìn)而對(duì)內(nèi)存進(jìn)行更加詳細(xì)的工作,而malloc/free不能。
new 是一個(gè)操作符,可以重載
malloc 是一個(gè)函數(shù),可以覆蓋
new 初始化對(duì)象,調(diào)用對(duì)象的構(gòu)造函數(shù),對(duì)應(yīng)的delete調(diào)用相應(yīng)的析構(gòu)函數(shù)
malloc 僅僅分配內(nèi)存,free僅僅回收內(nèi)存
二、寫(xiě)時(shí)拷貝
有一定經(jīng)驗(yàn)的程序員應(yīng)該都知道Copy On Write(寫(xiě)時(shí)復(fù)制)使用了“引用計(jì)數(shù)”,會(huì)有一個(gè)變量用于保存引用的數(shù)量。當(dāng)?shù)谝粋€(gè)類構(gòu)造時(shí),string的構(gòu)造函數(shù)會(huì)根據(jù)傳入的參數(shù)從堆上分配內(nèi)存,當(dāng)有其它類需要這塊內(nèi)存時(shí),這個(gè)計(jì)數(shù)為自動(dòng)累加,當(dāng)有類析構(gòu)時(shí),這個(gè)計(jì)數(shù)會(huì)減一,直到最后一個(gè)類析構(gòu)時(shí),此時(shí)的引用計(jì)數(shù)為1或是0,此時(shí),程序才會(huì)真正的Free這塊從堆上分配的內(nèi)存。
引用計(jì)數(shù)就是string類中寫(xiě)時(shí)才拷貝的原理!
什么情況下觸發(fā)Copy On Write(寫(xiě)時(shí)復(fù)制)
很顯然,當(dāng)然是在共享同一塊內(nèi)存的類發(fā)生內(nèi)容改變時(shí),才會(huì)發(fā)生Copy On Write(寫(xiě)時(shí)復(fù)制)。比如string類的[]、=、+=、+等,還有一些string類中諸如insert、replace、append等成員函數(shù)等,包括類的析構(gòu)時(shí)。
三、使用引用應(yīng)該注意什么?
《C++高級(jí)進(jìn)階教程》中指出,引用的底層實(shí)現(xiàn)由指針按照指針常量的方式實(shí)現(xiàn),見(jiàn):C++引用的本質(zhì)。非要說(shuō)區(qū)別,那么只能是使用上存在的區(qū)別。
引用就是對(duì)某個(gè)變量其別名。對(duì)引用的操作與對(duì)應(yīng)變量的操作的效果完全一樣。
申明一個(gè)引用的時(shí)候,切記要對(duì)其進(jìn)行初始化。 引用聲明完畢后,相當(dāng)于目標(biāo)變量名有兩個(gè)名稱,即該目標(biāo)原名稱和引用名,不能再把該引用名作為其他變量名的別名。聲明一個(gè)引用,不是新定義了一個(gè)變量,它只 表示該引用名是目標(biāo)變量名的一個(gè)別名,它本身不是一種數(shù)據(jù)類型,因此引用本身不占存儲(chǔ)單元,系統(tǒng)也 不給引用分配存儲(chǔ)單元。
不能建立數(shù)組的引用。 // 數(shù)組的元素不能是引用
定義引用的類型,是編譯時(shí)確定的, int a = 6; double &b = a;
詳見(jiàn):http://blog.csdn.net/scythe666/article/details/50976449
四、如何和一個(gè)函數(shù)共享一塊內(nèi)存地址
如果不用修改指針,只要傳指針過(guò)去,那邊用指針接收,如果需要修改指針。
指針的引用方法如下:
#include <stdio.h>void allocatmemory(float *&data) {data=new float[100]; }int main() {float *data = NULL;allocatmemory(data);if(!data){printf("data is null\r\n");}else{printf("data has been allocated memory.\r\n");delete []data;data = NULL;} }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
還有一種方法是利用指針的指針。
五、c++中多態(tài)體現(xiàn)
編譯時(shí)多態(tài):編譯期確定,重載,模板元編程
運(yùn)行時(shí)多態(tài):虛函數(shù),晚綁定
六、虛函數(shù)表存放的位置,一個(gè)類有多少個(gè)虛函數(shù)表?
詳見(jiàn):http://blog.csdn.net/scythe666/article/details/50977593
虛函數(shù)表的指針存在于對(duì)象實(shí)例中最前面的位置。虛函數(shù)表是類所擁有的,程序運(yùn)行過(guò)程中不能夠修改,它存放在常量區(qū)。
一個(gè)類若繼承了多個(gè)含有虛函數(shù)的基類,那么該類就有對(duì)應(yīng)數(shù)量的虛函數(shù)表。
七、vector、deque、list、set、map區(qū)別
1、vector
相當(dāng)于數(shù)組。在內(nèi)存中分配一塊連續(xù)的內(nèi)存空間進(jìn)行存儲(chǔ)。支持不指定vector大小的存儲(chǔ)。STL內(nèi)部實(shí)現(xiàn)時(shí),首先分配一個(gè)非常大的內(nèi)存空間預(yù)備進(jìn)行存儲(chǔ),即capacituy()函數(shù)返回的大小,當(dāng)超過(guò)此分配的空間時(shí)再整體重新放分配一塊內(nèi)存存儲(chǔ),這給人以vector可以不指定vector即一個(gè)連續(xù)內(nèi)存的大小的感覺(jué)。通常此默認(rèn)的內(nèi)存分配能完成大部分情況下的存儲(chǔ)。
優(yōu)點(diǎn):
(1) 不指定一塊內(nèi)存大小的數(shù)組的連續(xù)存儲(chǔ),即可以像數(shù)組一樣操作,但可以對(duì)此數(shù)組進(jìn)行動(dòng)態(tài)操作。通常體現(xiàn)在push_back() pop_back()
(2) 隨機(jī)訪問(wèn)方便,即支持[ ]操作符和vector.at()
(3) 節(jié)省空間。
缺點(diǎn):
(1) 在內(nèi)部進(jìn)行插入刪除操作效率低。
(2)只能在vector的最后進(jìn)行push和pop,不能在vector的頭進(jìn)行push和pop。
(3) 當(dāng)動(dòng)態(tài)添加的數(shù)據(jù)超過(guò)vector默認(rèn)分配的大小時(shí)要進(jìn)行整體的重新分配、拷貝與釋放
2、list
雙向鏈表。每一個(gè)結(jié)點(diǎn)都包括一個(gè)信息塊Info、一個(gè)前驅(qū)指針Pre、一個(gè)后驅(qū)指針Post。可以不分配必須的內(nèi)存大小方便的進(jìn)行添加和刪除操作。使用的是非連續(xù)的內(nèi)存空間進(jìn)行存儲(chǔ)。
優(yōu)點(diǎn):
(1) 不使用連續(xù)內(nèi)存完成動(dòng)態(tài)操作。
(2) 在內(nèi)部方便的進(jìn)行插入和刪除操作
(3) 可在兩端進(jìn)行push、pop
缺點(diǎn):
(1)不能進(jìn)行內(nèi)部的隨機(jī)訪問(wèn),即不支持[]操作符和vector.at()
>
(2)相對(duì)于verctor占用內(nèi)存多
3、deque
雙端隊(duì)列 double-end queue
deque是在功能上合并了vector和list。
優(yōu)點(diǎn):
(1) 隨機(jī)訪問(wèn)方便,即支持[ ]操作符和vector.at()
(2) 在內(nèi)部方便的進(jìn)行插入和刪除操作
(3) 可在兩端進(jìn)行push、pop
缺點(diǎn):
(1) 占用內(nèi)存多
使用區(qū)別:
(1)如果你需要高效的隨即存取,而不在乎插入和刪除的效率,使用vector
(2)如果你需要大量的插入和刪除,而不關(guān)心隨即存取,則應(yīng)使用list
(3)如果你需要隨即存取,而且關(guān)心兩端數(shù)據(jù)的插入和刪除,則應(yīng)使用deque
4、map是,key-value對(duì)集合
5、set,就是key=value的map
八、線程、進(jìn)程、協(xié)程區(qū)別和聯(lián)系
力薦插圖神作:http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html
1、進(jìn)程是一個(gè)具有獨(dú)立功能的程序關(guān)于某個(gè)數(shù)據(jù)集合的一次運(yùn)行活動(dòng)。它可以申請(qǐng)和擁有系統(tǒng)資源,是一個(gè)動(dòng)態(tài)的概念,是一個(gè)活動(dòng)的實(shí)體。它不只是程序的代碼,還包括當(dāng)前的活動(dòng),通過(guò)程序計(jì)數(shù)器的值和處理寄存器的內(nèi)容來(lái)表示。
進(jìn)程是一個(gè)“執(zhí)行中的程序”。程序是一個(gè)沒(méi)有生命的實(shí)體,只有處理器賦予程序生命時(shí),它才能成為一個(gè)活動(dòng)的實(shí)體,我們稱其為進(jìn)程。
2、通常在一個(gè)進(jìn)程中可以包含若干個(gè)線程,它們可以利用進(jìn)程所擁有的資源。在引入線程的操作系統(tǒng)中,通常都是把進(jìn)程作為分配資源的基本單位,而把線程作為獨(dú)立運(yùn)行和獨(dú)立調(diào)度的基本單位。由于線程比進(jìn)程更小,基本上不擁有系統(tǒng)資源,只擁有一點(diǎn)在運(yùn)行中必不可少的資源(如程序計(jì)數(shù)器,一組寄存器和棧),但是它可與同屬一個(gè)進(jìn)程的其他的線程共享進(jìn)程所擁有的全部資源。故對(duì)它的調(diào)度所付出的開(kāi)銷就會(huì)小得多,能更高效的提高系統(tǒng)內(nèi)多個(gè)程序間并發(fā)執(zhí)行的程度。
3、線程和進(jìn)程的區(qū)別在于,子進(jìn)程和父進(jìn)程有不同的代碼和數(shù)據(jù)空間,而多個(gè)線程則共享數(shù)據(jù)空間,每個(gè)線程有自己的執(zhí)行堆棧和程序計(jì)數(shù)器為其執(zhí)行上下文。多線程主要是為了節(jié)約CPU時(shí)間,發(fā)揮利用,根據(jù)具體情況而定。線程的運(yùn)行中需要使用計(jì)算機(jī)的內(nèi)存資源和CPU。
4、線程與進(jìn)程的區(qū)別歸納:
a.地址空間和其它資源:進(jìn)程間相互獨(dú)立,同一進(jìn)程的各線程間共享。某進(jìn)程內(nèi)的線程在其它進(jìn)程不可見(jiàn)。
b.通信:進(jìn)程間通信IPC,線程間可以直接讀寫(xiě)進(jìn)程數(shù)據(jù)段(如全局變量)來(lái)進(jìn)行通信——需要進(jìn)程同步和互斥手段的輔助,以保證數(shù)據(jù)的一致性。
c.調(diào)度和切換:線程上下文切換比進(jìn)程上下文切換要快得多。
d.在多線程O(píng)S中,進(jìn)程不是一個(gè)可執(zhí)行的實(shí)體。
5、優(yōu)缺點(diǎn)
線程和進(jìn)程在使用上各有優(yōu)缺點(diǎn):線程執(zhí)行開(kāi)銷小,但不利于資源的管理和保護(hù);而進(jìn)程正相反。同時(shí),線程適合于在SMP機(jī)器上運(yùn)行,而進(jìn)程則可以跨機(jī)器遷移。
協(xié)程詳見(jiàn):http://blog.csdn.net/scythe666/article/details/50987055
九、MySQL innodb myisam 區(qū)別
十、堆空間、棧空間區(qū)別
十一、64位程序指針多大
8字節(jié)
十二、函數(shù)內(nèi)、函數(shù)外 static 區(qū)別
十三、TCP三次握手和四次揮手
詳見(jiàn)http://blog.csdn.net/scythe666/article/details/50967632
十四、守護(hù)進(jìn)程和服務(wù)
十五、mysql跑了很久都沒(méi)有出結(jié)果,排除邏輯問(wèn)題,請(qǐng)問(wèn)如何檢測(cè)?
十六、session有什么缺點(diǎn)
十七、數(shù)據(jù)庫(kù)范式
十八、java反射機(jī)制
十九、java內(nèi)存回收,是否可以強(qiáng)制內(nèi)存回收
二十、c++有沒(méi)有內(nèi)存回收?
二十一、函數(shù)入口地址
如果你在調(diào)試程序時(shí)查看程序的匯編碼,可以發(fā)現(xiàn),調(diào)用函數(shù)的語(yǔ)句對(duì)應(yīng)的匯編碼是
jmp 函數(shù)名(入口地址)- 1
- 1
這樣的形式,函數(shù)在內(nèi)存中的存在形式就是一段代碼而已,入口地址即函數(shù)代碼段在內(nèi)存中的首地址。
二十二、如何判斷一個(gè)數(shù)是2的整數(shù)次方
我的分析過(guò)程是:
這個(gè)肯定是從二進(jìn)制入手,因?yàn)橛?jì)算機(jī)是二進(jìn)制處理,而且最關(guān)鍵的是2的整數(shù)次方是很特殊的 –> 二進(jìn)制中只有一個(gè)1。所以我想可以用二進(jìn)制來(lái)判斷1的個(gè)數(shù),寫(xiě)函數(shù)
x = x&(x-1); //每次減少一個(gè)1 cnt++;- 1
- 2
- 1
- 2
如果cnt為1,這是2的整數(shù)次方。這樣的方法還不是最簡(jiǎn)單的方法,可以直接看 x&(x-1) 是否為0即可。
二十三、兩個(gè)數(shù),如何判斷其中一個(gè)數(shù)的二進(jìn)制需要變換多少位才能到另一個(gè)數(shù)
分析:這題比較直接,很明顯也是到二進(jìn)制來(lái)處理,相同位放過(guò),不同就標(biāo)識(shí)為1,這樣自然聯(lián)想到異或操作,這就是異或操作的定義。
二十四、給10^8數(shù)量級(jí)的數(shù)組,其他數(shù)都是偶數(shù)次,只有一個(gè)數(shù)出現(xiàn)一次。如何快速找到這個(gè)數(shù)?
將所有數(shù)異或起來(lái),結(jié)果就是那個(gè)數(shù)。
二十五、10個(gè)文件,每個(gè)文件1G,如何排序?
分桶,桶與桶之間一定有大小關(guān)系,比如按照大小分100個(gè)桶,每個(gè)文件遍歷,分到桶里,桶內(nèi)排序,然后合起來(lái)就好。
二十六、c++ volatile
volatile 的意思是,“這個(gè)數(shù)據(jù)不知何時(shí)會(huì)被改變”,可能當(dāng)時(shí)環(huán)境正在被改變(可能有多任務(wù)、多線程或者中斷處理),所以 volatile 告訴編譯器不要擅自做出有關(guān)該數(shù)據(jù)的任何假定,優(yōu)化期間尤其如此。
volatile 的確切含義與具體機(jī)器相關(guān),可以通過(guò)閱讀編譯器文檔來(lái)理解,使用volatile的程序在移到新的機(jī)器或編譯器時(shí)通常必須改變。
與 const 限定符相同的,volatile 也是類型限定符。
與 const 類似的是,只能將 volatile 對(duì)象的地址賦給指向 volatile 的指針,或者將指向 volatile 類型的 volatile 類型的指針復(fù)制給指向 volatile 的指針。只有當(dāng)引用為 volatile 時(shí),才可以使用 volatile 對(duì)象對(duì)引用進(jìn)行初始化。
二十七、內(nèi)存對(duì)齊
以最大單位大小對(duì)齊,比如一個(gè) struct 中有 int[4]; 和 char
詳見(jiàn):http://blog.csdn.net/scythe666/article/details/50985461
二十八、lib和dll的區(qū)別
obj:目標(biāo)文件(二進(jìn)制)、通過(guò)鏈接器生成exe,obj給出程序的相對(duì)地址;exe給出絕對(duì)地址。
lib(編譯時(shí)):若干obj集合。
dll(運(yùn)行時(shí)):可實(shí)際執(zhí)行的二進(jìn)制代碼,包含可由多個(gè)程序同時(shí)使用的代碼和數(shù)據(jù)的庫(kù)。
不是可執(zhí)行文件,若知道dll函數(shù)原型,程序中LoadLibrary載入,getProAddress();
靜態(tài)鏈接使用靜態(tài)鏈接庫(kù):鏈接庫(kù)從靜態(tài)lib獲取引用函數(shù),應(yīng)用程序較大。
動(dòng)態(tài)鏈接:lib包含被dll導(dǎo)出的函數(shù)名和位置,dll包含實(shí)際函數(shù)和數(shù)據(jù),應(yīng)用程序用lib文件鏈接到dll文件。
區(qū)別總結(jié):
.dll用于運(yùn)行階段,如調(diào)用SetWindowText()函數(shù)等,需要在user32.dll中找到該函數(shù)。DLL可以簡(jiǎn)單認(rèn)為是一種包含供別人調(diào)用的函數(shù)和資源的可執(zhí)行文件。
.lib用于鏈接階段,在鏈接各部分目標(biāo)文件(通常為.obj)到可執(zhí)行文件(通常為.exe)過(guò)程中,需要在.lib文件中查找動(dòng)態(tài)調(diào)用函數(shù)(一般為DLL中的函數(shù))的地址信息,此時(shí)需要在lib文件中查找,如查找SetWindowText()函數(shù)的地址偏移就需要查找user32.lib文件。(.lib也可用于靜態(tài)鏈接的內(nèi)嵌代碼)
二十九、如何看到系統(tǒng)端口占用情況?這個(gè)方法底層實(shí)現(xiàn)是怎樣的?
三十、C++中的驟死式
如果 || 或者 && 如果判斷前面不符合要求,后面不會(huì)進(jìn)行計(jì)算
三十一、常見(jiàn)網(wǎng)絡(luò)錯(cuò)誤代碼
三十二、c++運(yùn)算符優(yōu)先級(jí)
三十三、c++運(yùn)算符重載
《劍指offer》上賦值運(yùn)算符重載
class whString { public:whString& operator = (const whString &str);whString () {m_pData = NULL;};whString(const char *s) {m_pData = new char[strlen(s) + 1];strcpy(m_pData,s);}~whString() {delete []m_pData;m_pData = NULL;}void stringPrint() {cout<<m_pData<<endl;} private:char *m_pData; };whString& whString::operator = (const whString &str) {cout<<"enter whString::operator =()"<<endl;if( &str == this ) //傳入的是否是同一個(gè)實(shí)例return *this;delete []m_pData;m_pData = NULL;m_pData = new char[strlen(str.m_pData) + 1];strcpy(m_pData,str.m_pData);return *this; }int main() {//freopen("input.txt","r",stdin);whString a = "abc";whString b;b = a;b.stringPrint();return 0; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
注意點(diǎn):
1、是否把返回值類型聲明為該類型引用,并返回實(shí)例自身引用(*this),這樣才允許連續(xù)賦值。
2、傳入?yún)?shù)聲明為const。
3、是否釋放自身內(nèi)存。
4、檢測(cè)是否傳入同一個(gè)參數(shù)。
如上代碼有更好的形式:
whString& whString::operator = (const whString &str) {cout<<"enter whString::operator =()"<<endl;if( &str != this ) {whString strTmp(str);char* pTmp = strTmp.m_pData;strTmp.m_pData = m_pData; //自動(dòng)調(diào)用析構(gòu)m_pData = pTmp;}return *this; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
避免了異常安全性。
三十四、c++ 模板元編程
詳見(jiàn):http://blog.csdn.net/scythe666/article/details/50899345
三十五、環(huán)境變量作用
三十六、包含目錄 庫(kù)目錄 附加依賴項(xiàng)【編譯器 參數(shù)詳解】
三十七、GPL LGPL 等開(kāi)源協(xié)議小覽
三十八、常說(shuō)的sdk、ide、jdk、jre、java runtime 區(qū)別
http://www.2cto.com/kf/201212/178270.html
SDK(Software Develop Kit,軟件開(kāi)發(fā)工具包),用于幫助開(kāi)發(fā)人員的提高工作效率。各種不同類型的軟件開(kāi)發(fā),都可以有自己的SDK。Windows有Windows SDK,DirectX 有 DirectX 9 SDK,.NET開(kāi)發(fā)也有Microsoft .NET Framework SDK。JAVA開(kāi)發(fā)也不含糊,也有自己的Java SDK。
java SDK最早叫Java Software Develop Kit,后來(lái)改名為JDK,即Java Develop Kit。
JDK作為Java開(kāi)發(fā)工具包,主要用于構(gòu)建在Java平臺(tái)上運(yùn)行的應(yīng)用程序、Applet 和組件等。
JRE(Java Runtime Environment,Java運(yùn)行環(huán)境),也就是Java平臺(tái)。所有的Java程序都要在JRE下才能運(yùn)行。JDK的工具也是Java程序,也需要JRE才能運(yùn)行。為了保持JDK的獨(dú)立性和完整性,在JDK的安裝過(guò)程中,JRE也是安裝的一部分。所以,在JDK的安裝目錄下有一個(gè)名為jre的目錄,用于存放JRE文件。
JVM(Java Virtual Machine,Java虛擬機(jī))是JRE的一部分。它是一個(gè)虛構(gòu)出來(lái)的計(jì)算機(jī),是通過(guò)在實(shí)際的計(jì)算機(jī)上仿真模擬各種計(jì)算機(jī)功能來(lái)實(shí)現(xiàn)的。JVM有自己完善的硬件架構(gòu),如處理器、堆棧、寄存器等,還具有相應(yīng)的指令系統(tǒng)。Java語(yǔ)言最重要的特點(diǎn)就是跨平臺(tái)運(yùn)行。使用JVM就是為了支持與操作系統(tǒng)無(wú)關(guān),實(shí)現(xiàn)跨平臺(tái)。
下圖清晰地展示了JDK(Java SDK)、JRE和JVM之間的關(guān)系:
三十九、注冊(cè)表詳細(xì)理解
四十、c++ 函數(shù)指針 指針函數(shù)
四十一、inline關(guān)鍵字
四十二、Lambda表達(dá)式
四十三、c++ 關(guān)鍵字整理
四十四、類的初始化列表
1、作用
2、什么樣的成員必須在初始化列表中初始化
3、初始化列表執(zhí)行時(shí)間
四十五、c++ 函數(shù)簽名
四十六、c++ 基本類型、復(fù)合類型
四十七、qmake 小覽
四十八、c++多重繼承 虛基類
四十九、cpu發(fā)展史
五十、域名解析過(guò)程
五十一、ebp esp 等寄存器作用
五十二、c++ 中隱藏、重寫(xiě)、覆蓋、重載區(qū)別
五十三、委托機(jī)制
五十四、extern關(guān)鍵字
五十五、DDos、SYNFLOOD攻擊
五十六、OS 主分區(qū)
五十七、宏函數(shù)
五十八、java類是什么負(fù)責(zé)創(chuàng)建的
五十九、郵件協(xié)議
http://www.tuicool.com/articles/MviQv2
1 郵件收發(fā)過(guò)程
電子郵件發(fā)送協(xié)議 是一種基于“ 推 ”的協(xié)議,主要包括 SMTP ; 郵件接收協(xié)議 則是一種基于“ 拉 ”的協(xié)議,主要包括 POP協(xié)議 和 IMAP協(xié)議 ,在正式介紹這些協(xié)議之前,我們先給出郵件收發(fā)的體系結(jié)構(gòu):
從上圖可以看出郵件收發(fā)的整個(gè)過(guò)程大致如下:
(1)發(fā)件人調(diào)用PC機(jī)中的用戶代理編輯要發(fā)送的郵件。
(2)發(fā)件人點(diǎn)擊屏幕上的”發(fā)送郵件“按鈕,把發(fā)送郵件的 工作全部交給用戶代理來(lái)完成。用戶代理通過(guò)SMTP協(xié)議將郵件發(fā)送給發(fā)送方的郵件服務(wù)器( 在這個(gè)過(guò)程中,用戶代理充當(dāng)SMTP客戶,而發(fā)送方的郵件服務(wù)器則充當(dāng)SMTP服務(wù)器 )。
(3)發(fā)送方的郵件服務(wù)器收到用戶代理發(fā)來(lái)的郵件后,就把收到的郵件臨時(shí)存放在郵件緩存隊(duì)列中,等待時(shí)間成熟的時(shí)候再發(fā)送到接收方的郵件服務(wù)器( 等待時(shí)間的長(zhǎng)短取決于郵件服務(wù)器的處理能力和隊(duì)列中待發(fā)送的信件的數(shù)量 )。
(4)若現(xiàn)在時(shí)機(jī)成熟了,發(fā)送方的郵件服務(wù)器則向接收方的郵件服務(wù)器發(fā)送郵件緩存中的郵件。在發(fā)送郵件之前,發(fā)送方的郵件服務(wù)器的SMTP客戶與接收方的郵件服務(wù)器的SMTP服務(wù)器需要事先建立TCP連接,之后再將隊(duì)列中 的郵件發(fā)送出去。 值得注意的是,郵件不會(huì)在因特網(wǎng)中的某個(gè)中間郵件服務(wù)器落地 。
(5)接收郵件服務(wù)器中的SMTP服務(wù)器進(jìn)程在收到郵件后,把郵件放入收件人的用戶郵箱中,等待收件人進(jìn)行讀取。
(6)收件人在打算收信時(shí),就運(yùn)行PC機(jī)中的用戶代理,使用POP3(或IMAP)協(xié)議讀取發(fā)送給自己的郵件。 注意,在這個(gè)過(guò)程中,收件人是POP3客戶,而接收郵件服務(wù)器則是POP3客戶,箭頭的方向是從郵件服務(wù)器指向接收用戶,因?yàn)檫@是一個(gè)“ 拉 ”的操作 。
2 電子郵件協(xié)議
http://server.zzidc.com/fwqfl/312.html
電子郵件在發(fā)送和接收的過(guò)程中還要遵循一些基本協(xié)議和標(biāo)準(zhǔn),這些協(xié)議主要有SMTP、POP3、IMAP、MIME等。
(1)SMTP協(xié)議
SMTP(Simple Mail Transfer Protocol,簡(jiǎn)單郵件傳輸協(xié)議)是Internet上基于TCP/IP的應(yīng)用層協(xié)議,使用于主機(jī)與主機(jī)之間的電子郵件交換。SMTP的特點(diǎn)是簡(jiǎn)單,它只定義了郵件發(fā)送方和接收方之間的連接傳輸,將電子郵件有一臺(tái)計(jì)算機(jī)傳送到另一臺(tái)計(jì)算機(jī),而不規(guī)定其他任何操作,如用戶界面的交互、郵件的接收、郵件存儲(chǔ)等。Internet上幾乎所有主機(jī)都運(yùn)行著遵循SMTP的電子郵件軟件,因此使用非常普通。另一方面,SMTP由于簡(jiǎn)單,因而有其一定的局限性,它只能傳送ASCII文本文件,而對(duì)于一些二進(jìn)制數(shù)據(jù)文件需要進(jìn)行編碼后才能傳送。
(2)POP3協(xié)議和IMAP協(xié)議
電子郵件用戶要從郵件服務(wù)器讀取或下載郵件時(shí)必須要有郵件讀取協(xié)議。現(xiàn)在常用的郵件讀取協(xié)議有兩個(gè),一個(gè)是郵局協(xié)議的第三版本(POP3,Post Office Protocol Version 3),另一個(gè)是因特網(wǎng)報(bào)文存取協(xié)議(IMAP,Internet Message Access Protocol)。
POP3是一個(gè)非常簡(jiǎn)單、但功能有限的郵件讀取協(xié)議,大多數(shù)ISP都支持POP3。當(dāng)郵件用戶將郵件接收軟件設(shè)定為POP3閱讀電子郵件時(shí),每當(dāng)使用者要閱讀電子郵件時(shí),它都會(huì)把所有信件內(nèi)容下載至使用者的計(jì)算機(jī),此外,他可選擇把郵件保留在郵件服務(wù)器上或是不保留郵件在服務(wù)器上。無(wú)IMAP是另一種郵件讀取協(xié)議。當(dāng)郵件用戶將郵件接收設(shè)定IMAP閱讀電子郵件時(shí),它并不會(huì)把所有郵件內(nèi)容下載至計(jì)算機(jī),而只下載郵件的主題等信息。
(3)多途徑Internet郵件擴(kuò)展協(xié)議
多用途Internet郵件擴(kuò)展協(xié)議(MIME,Multipose Internet Mail Extensions)是一種編碼標(biāo)準(zhǔn),它解決了SMTP只能傳送ASCII文本的限制。MIME定義了各種類型數(shù)據(jù),如聲音、圖像、表格、二進(jìn)制數(shù)據(jù)等的編碼格式,通過(guò)對(duì)這些類型的數(shù)據(jù)編碼并將它們作為郵件中的附件進(jìn)行處理,以保證這些部分內(nèi)容完整、正確地傳輸。因此,MIME增強(qiáng)了SMTP的傳輸功能,統(tǒng)一了編碼規(guī)范。
六十、c++用struct和class定義類型,有什么區(qū)別
如果沒(méi)有標(biāo)注成員函數(shù)或者成員變量的訪問(wèn)權(quán)限級(jí)別,在struct中默認(rèn)的是public,而在class中默認(rèn)的是private。
六十一、map reduce 基本知識(shí)
六十二、管程
管程 (英語(yǔ):Monitors,也稱為監(jiān)視器) 是一種程序結(jié)構(gòu),結(jié)構(gòu)內(nèi)的多個(gè)子程序(對(duì)象或模塊)形成的多個(gè)工作線程互斥訪問(wèn)共享資源。這些共享資源一般是硬件設(shè)備或一群變量。管程實(shí)現(xiàn)了在一個(gè)時(shí)間點(diǎn),最多只有一個(gè)線程在執(zhí)行管程的某個(gè)子程序。與那些通過(guò)修改數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)互斥訪問(wèn)的并發(fā)程序設(shè)計(jì)相比,管程實(shí)現(xiàn)很大程度上簡(jiǎn)化了程序設(shè)計(jì)。
簡(jiǎn)單點(diǎn)說(shuō)就是只能被單個(gè)線程執(zhí)行的代碼了,舉個(gè)例子假如一個(gè)管程類叫atm(取款機(jī)),里面有兩個(gè)方法叫提款 取款,不同的人為不同的線程,但是atm只允許一個(gè)人在一個(gè)時(shí)間段中進(jìn)行操作,也就是單線程,那么這個(gè)atm就需要一個(gè)鎖,單一個(gè)人在使用時(shí),其他的人只能wait。再者一個(gè)人如果使用的時(shí)間太長(zhǎng)也不行,所以需要一個(gè)條件變量來(lái)約束他
條件變量可以讓一個(gè)線程等待時(shí)讓另一線程進(jìn)入管程,這樣可以有效防止死鎖
六十三、子進(jìn)程可以訪問(wèn)父進(jìn)程的變量嗎?
答:
子進(jìn)程可以訪問(wèn)父進(jìn)程變量。子進(jìn)程“繼承”父進(jìn)程的數(shù)據(jù)空間,堆和棧,其地址總是一樣的。
因?yàn)樵趂ork時(shí)整個(gè)虛擬地址空間被復(fù)制,但是虛擬地址空間所對(duì)應(yīng)的物理內(nèi)存開(kāi)始卻沒(méi)有復(fù)制,如果有寫(xiě)入時(shí)寫(xiě)時(shí)拷貝。比如,這個(gè)時(shí)候父子進(jìn)程中變量 x對(duì)應(yīng)的虛擬地址和物理地址都相同,但等到虛擬地址空間被寫(xiě)時(shí),對(duì)應(yīng)的物理內(nèi)存空間被復(fù)制,這個(gè)時(shí)候父子進(jìn)程中變量x對(duì)應(yīng)的虛擬地址還是相同的,但是物理地址不同,這就是”寫(xiě)時(shí)復(fù)制”。還有父進(jìn)程和子進(jìn)程是始終共享正文段(代碼段)。
六十四、進(jìn)程間通信(IPC)的幾種方式?哪種效率最高?
答:
(1)管道PIPE和有名管道FIFO – 比如shell的重定向
(2)信號(hào)signal – 比如殺死某些進(jìn)程kill -9,比如忽略某些進(jìn)程nohup ,信號(hào)是一種軟件中斷
(3)消息隊(duì)列 – 相比共享內(nèi)存會(huì)慢一些,緩沖區(qū)有限制,但不用加鎖,適合命令等小塊數(shù)據(jù)。
(4)共享內(nèi)存 – 最快的IPC方式,同一塊物理內(nèi)存映射到進(jìn)程A、B各自的進(jìn)程地址空間,可以看到對(duì)方的數(shù)據(jù)更新,需要注意同步機(jī)制,比如互斥鎖、信號(hào)量。適合傳輸大量數(shù)據(jù)。
(5)信號(hào)量 – PV操作,生產(chǎn)者與消費(fèi)者示例;
(6)套接字 – socket網(wǎng)絡(luò)編程,網(wǎng)絡(luò)中不同主機(jī)間的進(jìn)程間通信,屬高級(jí)進(jìn)程間通信。
六十五、Linux多線程同步的幾種方式 ?
答:
(1)互斥鎖(mutex) (2)條件變量 (3)信號(hào)量。 如同進(jìn)程一樣,線程也可以通過(guò)信號(hào)量來(lái)實(shí)現(xiàn)同步,雖然是輕量級(jí)的。
這里要注意一點(diǎn),互斥量可通過(guò)pthread_mutex_setpshared接口設(shè)置可用于進(jìn)程間同步;條件標(biāo)量在初始化時(shí),也可以通過(guò)接口pthread_condattr_setpshared指定該條件變量可用于進(jìn)程進(jìn)程間同步。
六十六、多核與多個(gè)CPU的區(qū)別?
我們首先來(lái)了解下二者:
何為多核CPU?簡(jiǎn)單理解就是,我們將多個(gè)核心裝載一個(gè)封裝里,讓用戶理解成這是一個(gè)處理器。這樣好處就是原本運(yùn)行在單機(jī)上跑的程序基本不需要更改就能夠獲得非常不錯(cuò)的性能。多核心發(fā)展趨勢(shì)也是英特爾一直堅(jiān)持的方式。
何為多個(gè)CPU運(yùn)行呢?了解服務(wù)器的人都知道有單路,雙路,多路之分,而ARM針對(duì)服務(wù)器市場(chǎng)推出的處理器也是呈現(xiàn)這種方式,最終能夠形成分布式系統(tǒng),其實(shí)跟多核CPU內(nèi)部的分布式結(jié)果是一樣的,只不過(guò)那個(gè)從外部看是單個(gè)處理器。這種方式在軟件支持、運(yùn)行、故障方面的問(wèn)題較多。
下面我們舉一個(gè)例子來(lái)形象的比喻一下:
例如,你需要搬很多磚,你現(xiàn)在有一百只手。當(dāng)你將這一百只手全安裝到一個(gè)人身上,這模式就是多核。當(dāng)你將這一百之手安裝到50個(gè)人身上工作,這模式就是多CPU。
那么多核跟多CPU在應(yīng)用中有什么區(qū)別呢?首先我們看多核的模式,就是一個(gè)人身上安一百個(gè)手的方式,這個(gè)即使這個(gè)人再笨,干活速度也要比只有兩只手的人要快。
但是將一百只手放在一個(gè)人身上,同樣會(huì)帶來(lái)一些問(wèn)題,例如一百只手搬磚太多了,這樣身體的脊柱就受不了了,就會(huì)頂不住。這就是CPU的多核的極限。于是,當(dāng)搬磚數(shù)量較多的時(shí)候,多CPU的方式就顯現(xiàn)出來(lái)了。人多力量大呀。
六十七、軟中斷和硬中斷的區(qū)別?
答:
從本質(zhì)上來(lái)講,中斷是一種電信號(hào),當(dāng)設(shè)備有某種事件發(fā)生時(shí),它就會(huì)產(chǎn)生中斷,通過(guò)總線把電信號(hào)發(fā)送給中斷控制器。
如果中斷的線是激活的,中斷控制器就把電信號(hào)發(fā)送給處理器的某個(gè)特定引腳。處理器于是立即停止自己正在做的事,
跳到中斷處理程序的入口點(diǎn),進(jìn)行中斷處理。
①硬中斷是由外部設(shè)備對(duì)CPU的中斷,具有隨機(jī)性和突發(fā)性;軟中斷由程序控制,執(zhí)行中斷指令產(chǎn)生的、無(wú)外部施加的中斷請(qǐng)求信號(hào),因此不是隨機(jī)的而是安排好的。如信號(hào)就是軟件中斷,鍵盤(pán)輸入、鼠標(biāo)點(diǎn)擊就是硬件中斷。
②硬中斷的中斷響應(yīng)周期,CPU需要發(fā)中斷回合信號(hào)(NMI不需要),軟中斷的中斷響應(yīng)周期,CPU不需發(fā)中斷回合信號(hào)。
③硬中斷的中斷號(hào)是由中斷控制器提供的(NMI硬中斷中斷號(hào)系統(tǒng)指定為02H);軟中斷的中斷號(hào)由指令直接給出,無(wú)需使用中斷控制器。
④硬中斷是可屏蔽的(NMI硬中斷不可屏蔽),軟中斷不可屏蔽。
六十八、cpu指令集
指令集是存儲(chǔ)在CPU內(nèi)部,對(duì)CPU運(yùn)算進(jìn)行指導(dǎo)和優(yōu)化的硬程序。擁有這些指令集,CPU就可以更高效地運(yùn)行。Intel有x86,EM64T,MMX,SSE,SSE2,SSE3,SSSE3 (Super SSE3),SSE4.1,SSE4.2,AVX。AMD主要是x86,x86-64,3D-Now!指令集。
六十九、UDP和TCP可以綁定同一個(gè)端口?
答:
網(wǎng)絡(luò)中可以被命名和尋址的通信端口,是操作系統(tǒng)可分配的一種資源。
按照OSI七層協(xié)議的描述,傳輸層與網(wǎng)絡(luò)層在功能上的最大區(qū)別是傳輸層(第四層)提供進(jìn)程通信能力。從這個(gè)意義上講,網(wǎng)絡(luò)通信的最終地址就不僅僅是主機(jī)地址了,還包括可以描述進(jìn)程的某種標(biāo)識(shí)符。為此,TCP/IP協(xié)議提出了協(xié)議端口(protocol port,簡(jiǎn)稱端口)的概念,用于標(biāo)識(shí)通信的進(jìn)程。
端口是一種抽象的軟件結(jié)構(gòu)(包括一些數(shù)據(jù)結(jié)構(gòu)和I/O緩沖區(qū))。應(yīng)用程序(即進(jìn)程)通過(guò)系統(tǒng)調(diào)用與某端口建立連接(binding)后,傳輸層傳給該端口的數(shù)據(jù)都被相應(yīng)進(jìn)程所接收,相應(yīng)進(jìn)程發(fā)給傳輸層的數(shù)據(jù)都通過(guò)該端口輸出。在TCP/IP協(xié)議的實(shí)現(xiàn)中,端口操作類似于一般的I/O操作,進(jìn)程獲取一個(gè)端口,相當(dāng)于獲取本地唯一的I/O文件,可以用一般的讀寫(xiě)原語(yǔ)訪問(wèn)之。
也就是說(shuō):一個(gè)端口只能同時(shí)被分配給一個(gè)進(jìn)程
類似于文件描述符,每個(gè)端口都擁有一個(gè)叫端口號(hào)(port number)的整數(shù)型標(biāo)識(shí)符,用于區(qū)別不同端口。由于TCP/IP傳輸層的兩個(gè)協(xié)議TCP和UDP是完全獨(dú)立的兩個(gè)軟件模塊,因此各自的端口號(hào)也相互獨(dú)立,如TCP有一個(gè)255號(hào)端口,UDP也可以有一個(gè)255號(hào)端口,二者并不沖突。
端口號(hào)的分配是一個(gè)重要問(wèn)題。有兩種基本分配方式:第一種叫全局分配,這是一種集中控制方式,由一個(gè)公認(rèn)的中央機(jī)構(gòu)根據(jù)用戶需要進(jìn)行統(tǒng)一分配,并將結(jié)果公布于眾。第二種是本地分配,又稱動(dòng)態(tài)連接,即進(jìn)程需要訪問(wèn)傳輸層服務(wù)時(shí),向本地操作系統(tǒng)提出申請(qǐng),操作系統(tǒng)返回一個(gè)本地唯一的端口號(hào),進(jìn)程再通過(guò)合適的系統(tǒng)調(diào)用將自己與該端口號(hào)聯(lián)系起來(lái)(綁扎)。TCP/IP端口號(hào)的分配中綜合了上述兩種方式。TCP/IP將端口號(hào)分為兩部分,少量的作為保留端口,以全局方式分配給服務(wù)進(jìn)程。因此,每一個(gè)標(biāo)準(zhǔn)服務(wù)器都擁有一個(gè)全局公認(rèn)的端口(即周知口,well-known port),即使在不同機(jī)器上,其端口號(hào)也相同。剩余的為自由端口,以本地方式進(jìn)行分配。TCP和UDP均規(guī)定,小于256的端口號(hào)才能作保留端口。
再討論一下,一個(gè)服務(wù)器監(jiān)控一個(gè)端口,比如80端口,它為什么可以建立上成千上萬(wàn)的連接?
首先, 一個(gè)TCP連接需要由四元組來(lái)形成,即(src_ip,src_port,dst_ip,dst_port)。當(dāng)一個(gè)連接請(qǐng)求過(guò)來(lái)的時(shí)候,服務(wù)端調(diào)用accept函數(shù),新生成一個(gè)socket,這個(gè)socket所占用的本地端口依然是80端口。由四元組就很容易分析到了,同一個(gè)(src_ip,src_port),它所對(duì)應(yīng)的(dst_ip,dst_port)可以無(wú)窮變化,這樣就可以建立很多個(gè)客戶端的請(qǐng)求了。
七十、如何解決哲學(xué)家進(jìn)餐問(wèn)題?
答:
哲學(xué)家進(jìn)餐問(wèn)題是由荷蘭學(xué)者Dijkstra提出的經(jīng)典的線程和進(jìn)程間步問(wèn)題之一。產(chǎn)生死鎖的四個(gè)必要條件是:
(1)互斥條件;
(2)請(qǐng)求和保持條件;
(3)不可剝奪條件;
(4)環(huán)路等待條件。
筷子是絕對(duì)互斥的,我們可以破壞其它三種條件來(lái)解決哲學(xué)家進(jìn)餐問(wèn)題。解決辦法如下:
(1)破壞請(qǐng)求保持條件
利用原子思想完成。即只有拿起兩支筷子的哲學(xué)家才可以進(jìn)餐,否則,一支筷子也不拿。
(2)破壞不可剝奪條件
當(dāng)哲學(xué)家相互等待時(shí),選擇一個(gè)哲學(xué)家作為犧牲者,放棄手中的筷子,這樣就保證有一位哲學(xué)家可以就餐了。
(3)破壞環(huán)路等待條件
解法一:奇數(shù)號(hào)哲學(xué)家先拿他左邊的筷子,偶數(shù)號(hào)哲學(xué)家先拿他右邊的筷子。這樣破壞了同方向環(huán)路;
解法二:至多允許N-1位哲學(xué)家進(jìn)餐,將最后一個(gè)哲學(xué)家停止申請(qǐng)資源,斷開(kāi)環(huán)路。最終能保證有一位哲學(xué)家能進(jìn)餐,用完釋放兩只筷子,從而使更多的哲學(xué)家能夠進(jìn)餐。
七十一、堆排序和快速排序的區(qū)別?
答:
堆排序和快速排序都是比較類非線性比較類排序中較優(yōu)的排序方法,均是不穩(wěn)定排序,且平均時(shí)間復(fù)雜度均為O(nlogn)。區(qū)別有二:
(1)堆屬于選擇類排序,快速排序?qū)儆诮粨Q類排序;
(2)堆排序一般優(yōu)于快速排序的重要一點(diǎn)是,數(shù)據(jù)的初始分布情況對(duì)堆排序的效率沒(méi)有大的影響。
具體實(shí)現(xiàn)參考:十種常見(jiàn)排序算法。
七十二、反轉(zhuǎn)單鏈表
答:
ListNode* reverseList(ListNode* pHead){ListNode* pReverseHead=NULL;ListNode* pNode=pHead;ListNode* pPrev=NULL;while(pNode){ListNode* next=pNode->m_next; //先保存當(dāng)前被處理節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)if(NULL==next){//原鏈表的最后一個(gè)節(jié)點(diǎn)pReverseHead=pNode;break;}pNode->m_next=pPrev;//該節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)pPrev=pNode;pNode=next;}return pReverseHead; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
七十三、如何判斷單鏈表是否存在環(huán)?
答:
算法的思想是設(shè)定兩個(gè)指針p, q,其中p每次向前移動(dòng)一步,q每次向前移動(dòng)兩步。那么如果單鏈表存在環(huán),則p和q相遇;否則q將首先遇到null。
七十四、打印楊輝三角
#include <stdio.h> int main() {int a[10][10];int i,j;for(i=0;i<10;i++){a[i][0]=1;a[i][i]=1;}for(i=2;i<10;i++){for(j=1;j<i;j++)a[i][j]=a[i-1][j]+a[i-1][j-1];}for(i=0;i<10;i++){for(j=0;j<(10-i-1);++j)printf(" "); //每行前需要空的數(shù)的位置,每個(gè)數(shù)占4個(gè)空格for(j=0;j<=i;j++)printf("%4d ",a[i][j]);printf("\n");}return 0; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
七十五、虛基類的作用是什么,虛基類的實(shí)現(xiàn)機(jī)制就是什么呢?
答:
虛基類的作用是在C++多重繼承的情況下,如果出現(xiàn)菱形繼承的話,為了消除在子類中出現(xiàn)父類數(shù)據(jù)實(shí)體的多份拷貝。
虛基類的實(shí)現(xiàn)機(jī)制這個(gè)有點(diǎn)復(fù)雜。不同編譯器內(nèi)部實(shí)現(xiàn)的機(jī)制也不相同。其主要有兩種實(shí)現(xiàn)方案:
(1)是引入virtual base class table,不管多少個(gè)虛基類,總是只有一個(gè)指針指向它,這個(gè)virtual base class table(VBTBL)包括真正的 virtual base class 指針。
(2)Bjarne的辦法是在virtual function table中放置virtual base class的offset,而非地址,這個(gè)offset在virtual function table 的負(fù)位置(正值是索引virtual function,而負(fù)值則將方向盤(pán)引到virtual base class offsets)。
在VC++中,采用的是類似第一種方案。對(duì)每個(gè)繼承自虛基類的類實(shí)例,將增加一個(gè)隱藏的“虛基類表指針”(vbptr)成員變量,從而達(dá)到間接計(jì)算虛基類位置的目的。該變量指向一個(gè)全類共享的偏移量表,表中項(xiàng)目記錄了對(duì)于該類而言,“虛基類表指針”與虛基類之間的偏移量”,而不是真正的 virtual base class 指針,這就是說(shuō)類似于上面的第一種方案,而非嚴(yán)格按照該方案。具體參見(jiàn)C++虛繼承對(duì)象的內(nèi)存布局。
對(duì)于g++,實(shí)現(xiàn)上和VC++不同,它并沒(méi)有生成獨(dú)立的虛基類表和虛基類表指針來(lái)指明虛基類的偏移地址,具體實(shí)現(xiàn)細(xì)節(jié)我還不太清楚,可能《深度探索c++對(duì)象模型》會(huì)有說(shuō)明。這是只是測(cè)試了當(dāng)子類存在虛函數(shù)表指針和虛函數(shù)表時(shí),編譯器并不會(huì)為子類對(duì)象實(shí)體生成額外的一個(gè)虛基類表指針。
但是當(dāng)子類沒(méi)有虛函數(shù)表指針時(shí),編譯器會(huì)為子類對(duì)象生成一個(gè)指針變量,這個(gè)指針變量很可能就是指向虛基類表。種種跡象表明g++的實(shí)現(xiàn)方案和上面提到的第二種方案很相似,具體我沒(méi)有深入研究其對(duì)象布局,以后再探討我猜測(cè)的真?zhèn)巍?/p>
七十六、C++的單例模式
class CSingleton { private: CSingleton() //構(gòu)造函數(shù)是私有的 { } static CSingleton *m_pInstance; public: static CSingleton * GetInstance() { if(m_pInstance == NULL) //判斷是否第一次調(diào)用 m_pInstance = new CSingleton(); return m_pInstance; } };- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
七十七、數(shù)按位顛倒
七十八、TCP/IP 流量控制和擁塞控制
七十九、arp攻擊
arp 攻擊是:
ARP攻擊就是通過(guò)偽造IP地址和MAC地址實(shí)現(xiàn)ARP欺騙,能夠在網(wǎng)絡(luò)中產(chǎn)生大量的ARP通信量使網(wǎng)絡(luò)阻塞,攻擊者只要持續(xù)不斷的發(fā)出偽造的ARP響應(yīng)包就能更改目標(biāo)主機(jī)ARP緩存中的IP-MAC條目,造成網(wǎng)絡(luò)中斷或中間人攻擊。
八十、KMP的時(shí)間復(fù)雜度
O(m+n)
八十一、并查集
原問(wèn)題描述:有A、B兩個(gè)犯罪團(tuán)伙,給定n個(gè)人,然后給定m組關(guān)系,比如:r(1,2),代表1和2號(hào)犯人不在一個(gè)團(tuán)伙中,會(huì)隨機(jī)問(wèn)給定的兩個(gè)人在不在一個(gè)組織中,比如:q(x1,x2)。回答:是就是,不是就不是,不知道就不知道
八十二、如何在O(1)時(shí)間下,不申請(qǐng)空間前提下,刪除鏈表的某個(gè)節(jié)點(diǎn)。
交換后面的節(jié)點(diǎn)和當(dāng)前節(jié)點(diǎn),刪除下一個(gè)節(jié)點(diǎn)。但是對(duì)于最后一個(gè)節(jié)點(diǎn),只能從前往后找到pre節(jié)點(diǎn),這樣的復(fù)雜度是O(n),但是平均復(fù)雜度是O(1)
八十三、交換值
a = a^b; b = a^b; a = a^b;- 1
- 2
- 3
- 1
- 2
- 3
或者如下:
a = a + b; b = a - b; a = a - b;- 1
- 2
- 3
- 1
- 2
- 3
八十四、如果socket建立連接后,發(fā)送50000字節(jié),那邊可以接收到多少個(gè)?
根據(jù)真實(shí)的網(wǎng)絡(luò)環(huán)境,那邊可能會(huì)接收到不定的字節(jié)。
八十五、為什么拷貝構(gòu)造函數(shù)要用引用
不然會(huì)一直無(wú)限傳值,直到棧溢出。
八十六、如何讓一個(gè)類不能被繼承
構(gòu)造函數(shù)私有化
八十七、分頁(yè)算法和頁(yè)內(nèi)組織形式
八十八、如何判斷大端小端模式
八十九、如下代碼有什么問(wèn)題?
class CTest { public:int a;CTest() {memset(this,0,sizeof(*this)); }void printSize() {cout<<sizeof(*this)<<endl;} };int main() {//freopen("input.txt","r",stdin);CTest t;//t.printSize();return 0; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
引申:this指針?lè)旁谀睦?#xff1f;
九十、strcpy、memcpy、memmove區(qū)別?strcpy的結(jié)束標(biāo)志是什么?
九十一、new做了什么?重載operator new應(yīng)該注意什么?
new分配內(nèi)存+調(diào)用構(gòu)造函數(shù)
注意事項(xiàng):
(1)重載 operator new 的同時(shí)也需要一并重載 operator delete,因?yàn)槿绻{(diào)用 delete 是默認(rèn)的delete,這樣你在new重載里面做的事情只有你自己知道,默認(rèn)的不會(huì)去做,就會(huì)付出慘重的代價(jià)。
//這不是個(gè)很簡(jiǎn)單的事(詳細(xì)參考《Effective C++ Third Edition》 Item 51)。operator new 通常這樣編寫(xiě):// 這里并沒(méi)有考慮多線程訪問(wèn)的情況 void* operator new(std::size_t size) throw(std::bad_alloc) {using namespace std;// size == 0 時(shí) new 也必須返回一個(gè)合法的指針if (size == 0)size = 1;while (true) {//嘗試進(jìn)行內(nèi)存的分配if (內(nèi)存分配成功)return (成功分配的內(nèi)存的地址);// 內(nèi)存分配失敗時(shí),查找當(dāng)前的 new-handling function// 因?yàn)闆](méi)有直接獲取到 new-handling function 的辦法,因此只能這么做new_handler globalHandler = set_new_handler(0);set_new_handler(globalHandler);// 如果存在 new-handling function 則調(diào)用if (globalHandler) (*globalHandler)();// 不存在 new-handling function 則拋出異常else throw std::bad_alloc();} }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
(2)不要輕易重載全局 new(文件作用域)
重載 ::operator new() 的理由
Effective C++ 第三版第 50 條列舉了定制 new/delete 的幾點(diǎn)理由:
檢測(cè)代碼中的內(nèi)存錯(cuò)誤
優(yōu)化性能
獲得內(nèi)存使用的統(tǒng)計(jì)數(shù)據(jù)
這些都是正當(dāng)?shù)男枨?#xff0c;但是不重載 ::operator new() 也能達(dá)到同樣的目的。
http://www.360doc.com/content/12/1211/17/9200790_253442412.shtml
九十二、如下代碼sizeof輸出多少?如何強(qiáng)制內(nèi)存對(duì)齊?
struct TStruct {int a;char b;double c; };- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
跟順序相關(guān)。。。
1、結(jié)構(gòu)體成員變量相對(duì)于結(jié)構(gòu)體對(duì)象的首地址的偏移量是該成員變量類型大小的整數(shù)倍。
2、整個(gè)結(jié)構(gòu)體對(duì)象的最終大小是結(jié)構(gòu)體成員變量中類型大小最大的整數(shù)倍。
struct tmp {int aa;int bb;int cc; };struct tree {char c;double b;int a;tmp ss; };int main() {cout << sizeof(tmp) << endl;cout << sizeof(tree) << endl;return 0; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
結(jié)果顯示:
12
32
1+7+8+4+4+4+4 = 32
另:不要把被嵌套的結(jié)構(gòu)體當(dāng)成一個(gè)整體
如下代碼:
struct tmp {int aa;char bb;double cc; };struct TStruct {char c;double b;int a;tmp ss; };int main() {cout << sizeof(tmp) << endl;cout << sizeof(TStruct) << endl;return 0; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
輸出:
16
40
1+7+8+4+4+1+7+8 = 40
九十三、int a[100]; a+3是加了多少?
int a[100]; cout<<a<<endl; cout<<a+3<<endl;- 1
- 2
- 3
- 1
- 2
- 3
實(shí)測(cè)加了12
九十四、__stdcall、fastcall、__cdecl
調(diào)用規(guī)范簡(jiǎn)介
首先,要實(shí)現(xiàn)函數(shù)調(diào)用,除了要知道函數(shù)的入口地址外,還要向函數(shù)傳遞合適的參數(shù)。向被調(diào)函數(shù)傳遞參數(shù),可以有不同的方式實(shí)現(xiàn)。這些方式被稱為“調(diào)用規(guī)范”或“調(diào)用約定”。C/C++中常見(jiàn)的調(diào)用規(guī)范有__cdecl、__stdcall、__fastcall和__thiscall。
__cdecl調(diào)用約定
又稱為C調(diào)用約定,是C/C++默認(rèn)的函數(shù)調(diào)用約定,它的定義語(yǔ)法是:
- 1
- 2
- 1
- 2
約定的內(nèi)容有:
(1)參數(shù)入棧順序是從右向左;
(2)在被調(diào)用函數(shù) (Callee) 返回后,由調(diào)用方 (Caller)調(diào)整堆棧。
由于這種約定,C調(diào)用約定允許函數(shù)的參數(shù)的個(gè)數(shù)是不固定的,這也是C語(yǔ)言的一大特色。因?yàn)槊總€(gè)調(diào)用的地方都需要生成一段清理堆棧的代碼,所以最后生成的目標(biāo)文件較__stdcall、__fastcall調(diào)用方式要大,因?yàn)槊恳粋€(gè)主調(diào)函數(shù)在每個(gè)調(diào)用的地方都需要生成一段清理堆棧的代碼。
__stdcall調(diào)用約定
又稱為標(biāo)準(zhǔn)調(diào)用約定,申明語(yǔ)法是:
- 1
- 1
約定的內(nèi)容有:
(1)參數(shù)從右向左壓入堆棧;
(2)函數(shù)自身清理堆棧;
(3)函數(shù)名自動(dòng)加前導(dǎo)的下劃線,后面緊跟一個(gè)@符號(hào),其后緊跟著參數(shù)的尺寸;
(4)函數(shù)參數(shù)個(gè)數(shù)不可變。
__fastcall調(diào)用約定
又稱為快速調(diào)用方式。和__stdcall類似,它約定的內(nèi)容有:
(1) 函數(shù)的第一個(gè)和第二個(gè)DWORD參數(shù)(或者尺寸更小的)通過(guò)ecx和edx傳遞,其他參數(shù)通過(guò)從右向左的順序壓棧;
(2)被調(diào)用函數(shù)清理堆棧;
(3)函數(shù)名修改規(guī)則同stdcall。
其聲明語(yǔ)法為:
int __fastcall function(int a,int b);- 1
- 1
注意:不同編譯器編譯的程序規(guī)定的寄存器不同。在Intel 386平臺(tái)上,使用ECX和EDX寄存器。使用__fastcall方式無(wú)法用作跨編譯器的接口。
__thiscall調(diào)用約定
是唯一一個(gè)不能明確指明的函數(shù)修飾,因?yàn)閠hiscall不是關(guān)鍵字。它是C++類成員函數(shù)缺省的調(diào)用約定。由于成員函數(shù)調(diào)用還有一個(gè)this指針,因此必須特殊處理,thiscall意味著:
(1) 參數(shù)從右向左入棧;
(2) 如果參數(shù)個(gè)數(shù)確定,this指針通過(guò)ecx傳遞給被調(diào)用者;如果參數(shù)個(gè)數(shù)不確定,this指針在所有參數(shù)壓棧后被壓入堆棧;
(3)對(duì)參數(shù)個(gè)數(shù)不定的,調(diào)用者清理堆棧,否則函數(shù)自己清理堆棧。
http://blog.csdn.net/K346K346/article/details/47398243
九十五、工廠模式、裝飾者模式、觀察者模式類圖?MVC中M、V、C是單向的還是雙向
1、工廠模式
抽象工廠
九十六、編譯器斷點(diǎn)如何實(shí)現(xiàn)的
九十七、debug和release的區(qū)別是什么?為什么有時(shí)候在debug模式下運(yùn)行無(wú)誤,但在release模式下出錯(cuò)?編譯器debug模式在可執(zhí)行文件中加入了什么信息
(1)debug 中放入調(diào)試信息,比如符號(hào)表
(2)debug 是代碼直譯,release 可能有優(yōu)化,比如寄存器易失問(wèn)題。不用的變量去掉
九十八、如何最快把一個(gè)整數(shù)拆成3個(gè)小于它的 c 整數(shù)
九十九、ipc的幾種方式
(1)管道PIPE和有名管道FIFO – 比如shell的重定向
(2)信號(hào)signal – 比如殺死某些進(jìn)程kill -9,比如忽略某些進(jìn)程nohup ,信號(hào)是一種軟件中斷
(3)消息隊(duì)列 – 相比共享內(nèi)存會(huì)慢一些,緩沖區(qū)有限制,但不用加鎖,適合命令等小塊數(shù)據(jù)。
(4)共享內(nèi)存 – 最快的IPC方式,同一塊物理內(nèi)存映射到進(jìn)程A、B各自的進(jìn)程地址空間,可以看到對(duì)方的數(shù)據(jù)更新,需要注意同步機(jī)制,比如互斥鎖、信號(hào)量。適合傳輸大量數(shù)據(jù)。
(5)信號(hào)量 – PV操作,生產(chǎn)者與消費(fèi)者示例;
(6)套接字 – socket網(wǎng)絡(luò)編程,網(wǎng)絡(luò)中不同主機(jī)間的進(jìn)程間通信,屬高級(jí)進(jìn)程間通信。
一百、線程同步的方式
(1)互斥量(mutex)、(2)條件變量、(3)信號(hào)量。 如同進(jìn)程一樣,線程也可以通過(guò)信號(hào)量來(lái)實(shí)現(xiàn)同步,雖然是輕量級(jí)的。
這里要注意一點(diǎn),互斥量可通過(guò)pthread_mutex_setpshared接口設(shè)置可用于進(jìn)程間同步;條件標(biāo)量在初始化時(shí),也可以通過(guò)接口pthread_condattr_setpshared指定該條件變量可用于進(jìn)程進(jìn)程間同步。
一百零一、Unicode utf ansi具體是如何編碼的
utf-8 中文字符有些字符占2個(gè)有些3個(gè),英文字符都是1個(gè);ucs2 統(tǒng)一是2個(gè)
一百零二、冒泡復(fù)雜度、改進(jìn)冒泡
一百零三、計(jì)算快排和堆排復(fù)雜度?最好的排序算法?
一百零四、如何檢測(cè)內(nèi)存泄漏?
借鑒java的引用計(jì)數(shù)器
一百零五、如下 a 和 b 哪個(gè)地址大?
int main() {int a;int b;cout<<&a<<endl;cout<<&b<<endl;return 0; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
a地址更大,a先入棧。
一百零六、define 和 typedef 的區(qū)別
1、定義
define是宏定義,在預(yù)處理階段進(jìn)行字符串替換。
typedef是關(guān)鍵字,聲明類型別名,在編譯時(shí)處理(增加可讀性)。
2、define相當(dāng)于單純的字符串替換
#define int_ptr int* //不能顛倒位置 int_ptr a,b; //相當(dāng)于 int *a,b; a是復(fù)合類型int *,b 只是int- 1
- 2
- 1
- 2
- 1
- 2
- 1
- 2
3、跟const連用
typedef int* pint; #define PINT int* const pint P; //相當(dāng)于int* const P(const 修飾 int *),P的指向不能改 const PINT P; //相當(dāng)于const int* P,P指向的內(nèi)容不能改- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
4、typedef 語(yǔ)法上是一個(gè)存儲(chǔ)類的關(guān)鍵字,如 static、auto、extern、mutable、register。
typedef static int INT2; //編譯失敗,指定了一個(gè)以上的存儲(chǔ)類- 1
- 1
一般遵循:
define 定義“可讀”的變量以及一些宏語(yǔ)句任務(wù)(包括無(wú)參和帶參)
typedef 常用來(lái)定義關(guān)鍵字,冗長(zhǎng)的類型的別名
一百零七、ofstream
一百零八、32位/64位 基本類型變量會(huì)不同嗎
是的,c++基本數(shù)據(jù)類型的變量占據(jù)內(nèi)存字節(jié)數(shù)的多少根運(yùn)行平臺(tái)有關(guān)。
一百零九、如果用0-9、a、b、c表示32進(jìn)制的整數(shù),那10進(jìn)制數(shù)873085表示的是什么?
一百一十、如果父類指針指向子類,開(kāi)始運(yùn)行沒(méi)錯(cuò),但是后來(lái)崩潰了,可能原因是什么?
可能這個(gè)指針指向的空間已被釋放,或者是這個(gè)函數(shù)里面出錯(cuò)了。
一百一十一、可否寫(xiě)一個(gè)程序掃描整個(gè)內(nèi)存空間?
一百一十二、編譯鏈接做了什么
目標(biāo)程序又稱“目的程序”
由編譯程序?qū)⒃闯绦蚓幾g成與之等價(jià)的由機(jī)器碼構(gòu)成的,計(jì)算機(jī)能直接運(yùn)行的程序,該程序叫目標(biāo)程序。
鏈接器 (linker)
將一個(gè)個(gè)的目標(biāo)文件 ( 或許還會(huì)有若干程序庫(kù) ) 鏈接在一起生成一個(gè)完整的可執(zhí)行文件。
在符號(hào)解析 (symbol resolution) 階段,鏈接器按照所有目標(biāo)文件和庫(kù)文件出現(xiàn)在命令行中的順序從左至右依次掃描它們,在此期間它要維護(hù)若干個(gè)集合 :
(1) 集合 E 是將被合并到一起組成可執(zhí)行文件的所有目標(biāo)文件集合;
(2) 集合 U 是未解析符號(hào) (unresolved symbols ,比如已經(jīng)被引用但是還未被定義的符號(hào) ) 的集合;
(3) 集合 D 是所有之前已被加入到 E 的目標(biāo)文件定義的符號(hào)集合。一開(kāi)始, E 、 U 、 D 都是空的。
鏈接器的工作過(guò)程:
(1): 對(duì)命令行中的每一個(gè)輸入文件 f ,鏈接器確定它是目標(biāo)文件還是庫(kù)文件,如果它是目標(biāo)文件,就把 f 加入到 E ,并把 f 中未解析的符號(hào)和已定義的符號(hào)分別加入到 U 、 D 集合中,然后處理下一個(gè)輸入文件。
(2): 如果 f 是一個(gè)庫(kù)文件,鏈接器會(huì)嘗試把 U 中的所有未解析符號(hào)與 f 中各目標(biāo)模塊定義的符號(hào)進(jìn)行匹配。如果某個(gè)目標(biāo)模塊 m 定義了一個(gè) U 中的未解析符號(hào),那么就把 m 加入到 E 中,并把 m 中未解析的符號(hào)和已定義的符號(hào)分別加入到 U 、 D 集合中。不斷地對(duì) f 中的所有目標(biāo)模塊重復(fù)這個(gè)過(guò)程直至到達(dá)一個(gè)不動(dòng)點(diǎn) (fixed point) ,此時(shí) U 和 D 不再變化。而那些未加入到 E 中的 f 里的目標(biāo)模塊就被簡(jiǎn)單地丟棄,鏈接器繼續(xù)處理下一輸入文件。
(3): 如果處理過(guò)程中往 D 加入一個(gè)已存在的符號(hào) ,或者當(dāng)掃描完所有輸入文件時(shí) U 非空,鏈接器報(bào)錯(cuò)并停止動(dòng)作。否則,它把 E 中的所有目標(biāo)文件合并在一起生成可執(zhí)行文件。
這種”翻譯”通常有兩種方式,即編譯方式和解釋方式。編譯方式是指利用事先編好的一個(gè)稱為編譯程序的機(jī)器語(yǔ)言程序,
作為系統(tǒng)軟件存放在計(jì)算機(jī)內(nèi),當(dāng)用戶將高級(jí)語(yǔ)言編寫(xiě)的源程序輸入計(jì)算機(jī)后,編譯程序便把源程序整個(gè)地翻譯成用
機(jī)器語(yǔ)言表示的與之等價(jià)的目標(biāo)程序,然后計(jì)算機(jī)再執(zhí)行該目標(biāo)程序,以完成源程序要處理的運(yùn)算并取得結(jié)果。
解釋方式是指源程序進(jìn)入計(jì)算機(jī)后,解釋程序邊掃描邊解釋,逐句輸入逐句翻譯,計(jì)算機(jī)一句句執(zhí)行,并不產(chǎn)生目標(biāo)程序。
http://blog.chinaunix.net/uid-11572501-id-2868702.html
一百一十三、可變參函數(shù)
#include <stdarg.h> // 必須包含的頭文件int Add(int start,...) // ...是作為占位符 { va_list arg_ptr; // 定義變參起始指針int sum=0; // 定義變參的和int nArgValue =start; // va_start(arg_ptr,start); // arg_ptr指向第一個(gè)變參do {sum+=nArgValue; // 求和nArgValue = va_arg(arg_ptr,int); // arg_ptr指向下一個(gè)變參} while(nArgValue != 0); // 判斷結(jié)束條件;結(jié)束條件是自定義為=0時(shí)結(jié)束va_end(arg_ptr); // 復(fù)位指針return sum; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
函數(shù)的調(diào)用方法為Add(1,2,3,0);這樣,必須以0結(jié)尾,因?yàn)樽儏⒑瘮?shù)結(jié)束的判斷條件就是讀到0停止。
解釋:
所使用到的宏:
void va_start( va_list arg_ptr, prev_param );
type va_arg( va_list arg_ptr, type );
void va_end( va_list arg_ptr );
typedef char * va_list;
#define _INTSIZEOF(n) ((sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
#define va_arg(ap,t) ( (t )((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_end(ap) ( ap = (va_list)0 )
1、首先把va_list被定義成char*,這是因?yàn)樵谖覀兡壳八玫腜C機(jī)上,字符指針類型可以用來(lái)存儲(chǔ)內(nèi)存單元地址。而在有的機(jī)器上va_list是被定義成void*的
2、定義_INTSIZEOF(n)主要是為了某些需要內(nèi)存的對(duì)齊的系統(tǒng).這個(gè)宏的目的是為了得到最后一個(gè)固定參數(shù)的實(shí)際內(nèi)存大小。在我的機(jī)器上直接用sizeof運(yùn)算符來(lái)代替,對(duì)程序的運(yùn)行結(jié)構(gòu)也沒(méi)有影響。(后文將看到我自己的實(shí)現(xiàn))。
3、va_start的定義為 &v+_INTSIZEOF(v) ,這里&v是最后一個(gè)固定參數(shù)的起始地址,再加上其實(shí)際占用大小后,就得到了第一個(gè)可變參數(shù)的起始內(nèi)存地址。所以我們運(yùn)行va_start(ap, v)以后,ap指向第一個(gè)可變參數(shù)在的內(nèi)存地址,有了這個(gè)地址,以后的事情就簡(jiǎn)單了。
這里要知道兩個(gè)事情:
⑴在intel+windows的機(jī)器上,函數(shù)棧的方向是向下的,棧頂指針的內(nèi)存地址低于棧底指針,所以先進(jìn)棧的數(shù)據(jù)是存放在內(nèi)存的高地址處。
(2)在VC等絕大多數(shù)C編譯器中,默認(rèn)情況下,參數(shù)進(jìn)棧的順序是由右向左的,因此,參數(shù)進(jìn)棧以后的內(nèi)存模型如下圖所示:最后一個(gè)固定參數(shù)的地址位于第一個(gè)可變參數(shù)之下,并且是連續(xù)存儲(chǔ)的。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
(4) va_arg():有了va_start的良好基礎(chǔ),我們?nèi)〉昧说谝粋€(gè)可變參數(shù)的地址,在va_arg()里的任務(wù)就是根據(jù)指定的參數(shù)類型取得本參數(shù)的值,并且把指針調(diào)到下一個(gè)參數(shù)的起始地址。
因此,現(xiàn)在再來(lái)看va_arg()的實(shí)現(xiàn)就應(yīng)該心中有數(shù)了:
#define va_arg(ap,t) ( (t )((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
這個(gè)宏做了兩個(gè)事情,
①用用戶輸入的類型名對(duì)參數(shù)地址進(jìn)行強(qiáng)制類型轉(zhuǎn)換,得到用戶所需要的值
②計(jì)算出本參數(shù)的實(shí)際大小,將指針調(diào)到本參數(shù)的結(jié)尾,也就是下一個(gè)參數(shù)的首地址,以便后續(xù)處理。
(5)va_end宏的解釋:x86平臺(tái)定義為ap=(char*)0;使ap不再 指向堆棧,而是跟NULL一樣.有些直接定義為((void*)0),這樣編譯器不會(huì)為va_end產(chǎn)生代碼,例如gcc在Linux的x86平臺(tái)就是這樣定義的. 在這里大家要注意一個(gè)問(wèn)題:由于參數(shù)的地址用于va_start宏,所以參數(shù)不能聲明為寄存器變量或作為函數(shù)或數(shù)組類型. 關(guān)于va_start, va_arg, va_end的描述就是這些了,我們要注意的 是不同的操作系統(tǒng)和硬件平臺(tái)的定義有些不同,但原理卻是相似的.
一百一十四、函數(shù)簽名
C++函數(shù)簽名包括 函數(shù)名、參數(shù)個(gè)數(shù)、參數(shù)類型
不包括返回類型
c語(yǔ)言函數(shù)簽名只包含函數(shù)名
一百一十五、要實(shí)現(xiàn)一個(gè)云盤(pán),應(yīng)該如何分模塊?
個(gè)人觀點(diǎn):
按照用戶動(dòng)作流來(lái)劃分是最直觀的。
client端有:文件安全監(jiān)測(cè)模塊,md5生成模塊
傳輸模塊
server端有:存儲(chǔ)模塊(包括文件副本計(jì)數(shù)器+冗余備份)、用戶模塊(用戶管理+用戶文件對(duì)應(yīng)表)
一百一十六、云盤(pán)如何判斷一個(gè)文件安全性?
后綴名+病毒特征碼
一百一十七、云盤(pán)傳輸過(guò)程中,應(yīng)該選擇TCP還是UDP?如何選擇第5層協(xié)議?
udp可以手工實(shí)現(xiàn)重傳。
一百一十八、給一個(gè)10T硬盤(pán)空間,在沒(méi)有文件系統(tǒng)的情況下,云盤(pán)文件應(yīng)該如何組織?最好不要用到db。
這里需要說(shuō)明一下,有沒(méi)有文件系統(tǒng),跟程序得到的地址是不是虛擬地址沒(méi)有關(guān)系。虛擬地址和物理地址的映射關(guān)系是內(nèi)核做的。
一百一十九、用戶和文件如何組織?還有用戶可能對(duì)應(yīng)目錄和文件,目錄可以嵌套,應(yīng)該如何組織?
一百二十、用戶云盤(pán)上傳下載慢,可能原因有哪些?
1、沒(méi)充會(huì)員
2、運(yùn)營(yíng)商不同
3、ddos攻擊
4、服務(wù)器和用戶太遠(yuǎn),路由跳數(shù)太多
5、服務(wù)器訪問(wèn)量太大
一百二十一、如何監(jiān)測(cè)磁盤(pán)瞬時(shí)讀寫(xiě)量過(guò)大?
一百二十二、STL容器
(1)標(biāo)準(zhǔn)STL序列容器:vector、string、deque(雙向)、list(雙向)
(2)標(biāo)準(zhǔn)STL關(guān)聯(lián)容器:set(值唯一)、multiset、map、multimap
(3)非標(biāo)準(zhǔn)序列容器:slist(單向)和 rope
(4)非標(biāo)準(zhǔn)的關(guān)聯(lián)容器:hash_set、hash_multiset、hash_map、hash_multimap
(5)幾種標(biāo)準(zhǔn)的非STL容器:數(shù)組、bitset、stack、queue 和 priority_queue
關(guān)于容器內(nèi)存存儲(chǔ)方式
(1)連續(xù)內(nèi)存容器:元素放在一或多塊內(nèi)存,每塊內(nèi)存多個(gè)元素,插入或刪除時(shí),同一內(nèi)存塊其他元素也會(huì)發(fā)生移動(dòng), vector,string,deque,rope
(2)基于節(jié)點(diǎn)的容器:內(nèi)個(gè)內(nèi)存塊只放一個(gè)元素,list,slist,標(biāo)準(zhǔn)關(guān)聯(lián)容器,非標(biāo)準(zhǔn)的哈希容器。
建議:
(1)vector、deque、list:vector默認(rèn),序列中間頻繁插入刪除,用list,頭尾插入刪除,用deque。
(2)任意位置插入:選擇序列容器
(3)隨機(jī)訪問(wèn)迭代器:用vector、deque、string、rope
(4)考慮元素查找速度:hash容器、排序vector,標(biāo)準(zhǔn)關(guān)聯(lián)容器
(5)插入刪除,需要事務(wù)語(yǔ)義:基于節(jié)點(diǎn)(每個(gè)內(nèi)存塊只放一個(gè)元素,list、slist)
一百二十三、struct和class
struct:默認(rèn)public(成員/繼承),編譯器不為struct保留內(nèi)存空間。
class:默認(rèn) private(成員/繼承),為類保留
兩者都可以繼承、構(gòu)造/析構(gòu)、多態(tài)
一百二十四、cpu的位數(shù),操作系統(tǒng)的位數(shù),編譯器中編譯的位數(shù)有什么關(guān)聯(lián)
一百二十五、一共有10t貨物,裝到若干箱子中,箱子最多裝1t貨物(不考慮箱子數(shù)量)。現(xiàn)在有載重3t的貨車,問(wèn)至少要多少輛車一定能裝完這些貨物?
http://www.mofangge.com/html/qDetail/02/c0/201310/b88kc002360282.html
有幾個(gè)地方要想通:
(1)不是4就是5
(2)每個(gè)箱子平均比不平均更容易造成4輛車裝不完的局面
(3)在(2)成立的條件下,如果分的箱子越少,越容易造成4輛車裝不完,因?yàn)轭w粒越小越容易勻開(kāi)。
(4)在(2)成立條件下,必須不能被4整除,否則每輛車2.5噸一定可以搞定。
這樣就可以列出下面的編程公式:
y代表箱子的個(gè)數(shù),那么 10/y 代表每個(gè)箱子重量。
通過(guò)編程累加y到一個(gè)上限(個(gè)人感覺(jué)100足以),如果存在y,就證明4輛裝不完。
可以求出,y為13的時(shí)候成立
一百二十六、樹(shù)和hash_map的優(yōu)缺點(diǎn)
一百二十七、效率優(yōu)先的情況下,輸入一些0-99999的數(shù),實(shí)現(xiàn)一個(gè)數(shù)據(jù)結(jié)構(gòu),高效完成刪除、插入、查找、遍歷、計(jì)數(shù)個(gè)數(shù)
一百二十八、MIN_INT
今天在看《深入理解計(jì)算機(jī)系統(tǒng)》的時(shí)候,在p105頁(yè)作者給出了INT_MIN在標(biāo)準(zhǔn)頭文件limits.h中的定義
#define INT_MAX 2147483647 #define INT_MIN (-INT_MAX - 1)- 1
- 2
- 1
- 2
這里沒(méi)有簡(jiǎn)單地將INT_MIN賦值成-2147483647,是因?yàn)?2147483648對(duì)于編譯器而言是個(gè)表達(dá)式,而2147483648對(duì)于32-bit整數(shù)是無(wú)法表示的,所以經(jīng)過(guò)這個(gè)表達(dá)式的結(jié)果是未定義的。在GCC上直接寫(xiě)-2147483648后,編譯器給出了警告,說(shuō)結(jié)果是unsigned。
這里有一篇文章提到了其中的緣由,可以參考:INT_MIN
十六進(jìn)制輸入,應(yīng)該輸入的就是計(jì)算機(jī)的存放方式,是補(bǔ)碼存放。
比如:
int main() {//freopen("input.txt","r",stdin);int a = INF;int maxInt = 0x7fffffff; //最大intint minusOne = 0xffffffff; //-1int minInt = 0x80000000; //最小intint minusMaxInt = 0x80000001; //-maxIntreturn 0; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
http://blog.csdn.net/seizef/article/details/7605010
一百二十九、如何傳入一個(gè)數(shù)組,而不退化為指針?
void func(int (&b) [20][10]) { //通過(guò)數(shù)組的引用 }void func(int *b) {}int main() { //freopen("input.txt","r",stdin); int a[20][10]; a[2][1] = 5; func(a); return 0; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
現(xiàn)在又有一個(gè)問(wèn)題:如果構(gòu)成指針和引用數(shù)組這樣的重載,到底先進(jìn)哪一個(gè)?
我的思考是,應(yīng)該進(jìn)引用那個(gè),因?yàn)轭愃朴?int 和 double ,func(5) 會(huì)優(yōu)先選用 int,就在于數(shù)組a類型原本是數(shù)組,所以會(huì)優(yōu)先用原類型。
引用的確是傳的數(shù)組,而傳值是傳遞的指針,編譯器將其退化了
如果是傳引用,調(diào)試的時(shí)候有寬度限制(行下標(biāo)從0-19),這就證明是數(shù)組,打印sizeof是20*10*4= 800
如果是指針,只有一個(gè)指針的地址,而且打印sizeof也是一個(gè)指針的值:
一百三十、如何返回一個(gè)數(shù)組?
一百三十一、可不可以將int b[4]傳給參數(shù)int a[5]
答案是:傳值可以,引用不行
數(shù)組傳值那邊退化為指針
一百三十二、關(guān)于數(shù)組越界
不論讀寫(xiě)都不會(huì)報(bào)錯(cuò),測(cè)試平臺(tái)vs2012
那當(dāng)數(shù)組影響到其他變量的時(shí)候會(huì)不會(huì)報(bào)錯(cuò)呢,比如在函數(shù)棧中定義一些其他變量,數(shù)組越界寫(xiě)到別的地方。
還真寫(xiě)進(jìn)去了(可能會(huì)崩潰),也就是說(shuō),數(shù)組底層跟指針是類似的,可以任意訪問(wèn)非法空間。
一百三十三、一個(gè)程序一直進(jìn)不了main函數(shù),可能原因是什么?
main函數(shù)不一定是第一個(gè)運(yùn)行的函數(shù),比如全局類的構(gòu)造函數(shù)。
一百三十四、c++中可以打印當(dāng)前函數(shù)地址嗎?
一百三十五、vs中條件斷點(diǎn)+內(nèi)存斷點(diǎn)
一百三十六、什么是線程安全
如果你的代碼所在的進(jìn)程中有多個(gè)線程在同時(shí)運(yùn)行,而這些線程可能會(huì)同時(shí)運(yùn)行這段代碼。如果每次運(yùn)行結(jié)果和單線程運(yùn)行的結(jié)果是一樣的,而且其他的變量的值也和預(yù)期的是一樣的,就是線程安全的。
或者說(shuō):一個(gè)類或者程序所提供的接口對(duì)于線程來(lái)說(shuō)是原子操作或者多個(gè)線程之間的切換不會(huì)導(dǎo)致該接口的執(zhí)行結(jié)果存在二義性,也就是說(shuō)我們不用考慮同步的問(wèn)題。
線程安全問(wèn)題都是由全局變量及靜態(tài)變量引起的。
若每個(gè)線程中對(duì)全局變量、靜態(tài)變量只有讀操作,而無(wú)寫(xiě)操作,一般來(lái)說(shuō),這個(gè)全局變量是線程安全的;若有多個(gè)線程同時(shí)執(zhí)行寫(xiě)操作,一般都需要考慮線程同步,否則的話就可能影響線程安全。
1.局部變量局部使用是安全的
為什么?因?yàn)槊總€(gè)thread 都有自己的運(yùn)行堆棧,而局部變量是生存在堆棧中,大家不干擾。
所以代碼1
int local1;
++local1;
是安全的
2.全局原生變量多線程讀寫(xiě)是不安全的
全局變量是在堆(heap)中
long global1 = 0;
++global2;
++這個(gè)操作其實(shí)分為兩部,一個(gè)是讀,另外一個(gè)是寫(xiě)
mov ecx,global
add ecx,1
mov global,ecx
所以代碼3處是不安全的
3.函數(shù)靜態(tài)變量多線程讀寫(xiě)也是不安全的
道理同2
所以代碼2處也是不安全的
4.volatile能保證全局整形變量是多線程安全的么
不能。
volatile僅僅是告誡compiler不要對(duì)這個(gè)變量作優(yōu)化,每次都要從memory取數(shù)值,而不是從register
所以代碼4也不是安全
5.InterlockedIncrement保證整型變量自增的原子性
所以代碼5是安全的
6.function static object的初始化是多線程安全的么
不是。
著名的Meyer Singleton其實(shí)不是線程安全的
Object & getInstance()
{
static Object o;
return o;
}
可能會(huì)造成多次初始化對(duì)象
所以代碼6處是不安全的
7.在32機(jī)器上,4字節(jié)整形一次assign是原子的
比如
i =10; //thread1
i=4; //thread2
不會(huì)導(dǎo)致i的值處于未知狀態(tài),要么是10要么是4
寫(xiě)好多線程安全的法寶就是封裝,使數(shù)據(jù)有保護(hù)的被訪問(wèn)到
安全性:
局部變量>成員變量>全局變
一百三十七、RTTI
一百三十八、java循環(huán)左移、右移
此題在編程之美中用到,截圖留念:
byte a=112,用程序?qū)崿F(xiàn),將其循環(huán)左移三位和右移三位。
112的二進(jìn)制原碼:0111 0000
112循環(huán)左移3位后的二進(jìn)制碼:1000 0011
112循環(huán)右移3位后的二進(jìn)制碼:0000 1110
先將循環(huán)左移的程序代碼告訴大家:
public class TestCircle{public static void main(String args[]){byte x=112;System.out.println((byte)(x<<3|x>>5));} }- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
程序的輸出結(jié)果是-125,它的原碼為1111 1101,補(bǔ)碼為1000 0011(正好是112循環(huán)左移三位后的數(shù)字)
再看循環(huán)右移的程序代碼:
public class TestCircle{public static void main(String args[]){byte x=112;System.out.println((byte)(x>>3|x<<5));} }- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
程序的輸出結(jié)果是14,他的原碼、補(bǔ)碼相同都是0000 1110(正好是112循環(huán)右移三位后的數(shù)字)
總結(jié):對(duì)于一個(gè)數(shù)據(jù)類型長(zhǎng)度為L(zhǎng)的數(shù)據(jù)n,對(duì)其進(jìn)行循環(huán)左移m位(或右移m位),只需將數(shù)據(jù)n左移(或右移)m位的結(jié)果和數(shù)據(jù)n右移(或左移)L-m位的結(jié)果進(jìn)行或運(yùn)算,再將或運(yùn)算的結(jié)果強(qiáng)制轉(zhuǎn)換為原類型即可。
一百三十九、printf(“abc”+1);
答案是輸出”bc”,可能是一個(gè)字符數(shù)組收地址,后面加的數(shù)字代表移動(dòng)的位數(shù)
一百四十. 遍歷刪除stl迭代器引發(fā)的錯(cuò)誤
(1)對(duì)于節(jié)點(diǎn)式容器(map, list, set)元素的刪除,插入操作會(huì)導(dǎo)致指向該元素的迭代器失效,其他元素迭代器不受影響;
(2)對(duì)于順序式容器(vector,string,deque)元素的刪除、插入操作會(huì)導(dǎo)致指向該元素以及后面的元素的迭代器失效。
http://ivan4126.blog.163.com/blog/static/209491092201351441333357/
正確刪除法一:
(1)當(dāng)刪除特定值的元素時(shí),刪除元素前保存當(dāng)前被刪除元素的下一個(gè)元素的迭代器。
map<string,int >::iterator nextIt=countMap.begin();for(map<string,int>::iterator it=countMap.begin(); ; ){if(nextIt!=countMap.end())++nextIt;else break;if(it->second==2){countMap.erase(it);}it=nextIt; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
(2)如何更加簡(jiǎn)潔的實(shí)現(xiàn)該方法呢?下面給出該方法的《Effective STL》一書(shū)的具體實(shí)現(xiàn):
for(auto iter1 = theMap.begin(); iter1 != theMap.end(); ) {if(iter1->second == xxx){theMap.erase(iter1++); //#1 }else{++iter1;} }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
(3)也可以實(shí)現(xiàn)如下,利用函數(shù)返回值(返回下一個(gè)iterator)
for(map<string,int>::iterator it=countMap.begin();it!=countMap.end();){if(it->second==2){it=countMap.erase(it);}else++it; }- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
正確刪除法二:
使用 remove_copy_if 實(shí)現(xiàn)
當(dāng)刪除滿足某些條件的元素,可以使用remove_copy_if & swap方法。當(dāng)然,方法一的滿足特性值是滿足某些條件的特例,因此,也可以應(yīng)用此方法。
那么如何通過(guò)remove_copy_if 刪除 map< string,int>中的元素呢?網(wǎng)上很少有給出map的實(shí)現(xiàn),一般都是以vector為例。所以這里給出我的實(shí)現(xiàn)。
在通過(guò)remove_copy_if 按照條件拷貝了需要的元素之后,如何實(shí)現(xiàn)兩個(gè)map的交換,可以直接調(diào)用map的成員函數(shù)swap。參考代碼:
#include <iostream> #include <string> #include <map> #include <algorithm> #include <iterator> using namespace std;map<string,int> mapCount;//不拷貝的條件 bool notCopy(pair<string,int> key_value){return key_value.second==1; }int main(){mapCount.insert(make_pair("000",0));mapCount.insert(make_pair("001",1));mapCount.insert(make_pair("002",2));mapCount.insert(make_pair("003",1));map<string,int> mapCountTemp;//臨時(shí)map容器//之所以要用inserter()函數(shù)是因?yàn)橥ㄟ^(guò)調(diào)用insert()成員函數(shù)來(lái)插入元素,并由用戶指定插入位置remove_copy_if(mapCount.begin(),mapCount.end(),inserter(mapCountTemp,mapCountTemp.begin()),notCopy);mapCount.swap(mapCountTemp);//實(shí)現(xiàn)兩個(gè)容器的交換cout<<mapCount.size()<<endl; //輸出2cout<<mapCountTemp.size()<<endl; //輸出4//驗(yàn)證//正確輸出://000 0//002 2for(map<string,int>::iterator it=mapCount.begin();it!=mapCount.end();++it){cout<<it->first<<" "<<it->second<<endl;}getchar(); }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
這種方法的缺點(diǎn):雖然實(shí)現(xiàn)兩個(gè)map的交換的時(shí)間復(fù)雜度是常量級(jí),一般情況下,拷貝帶來(lái)的時(shí)間開(kāi)銷會(huì)大于刪除指定元素的時(shí)間開(kāi)銷,并且臨時(shí)map容器也增加了空間的開(kāi)銷。
總結(jié):
關(guān)于容器的刪除,有篇blog總結(jié)的很好,現(xiàn)在轉(zhuǎn)貼如下:
刪除容器中具有特定值的元素:
(1)如果容器是vector、string或者deque,使用erase-remove的慣用法。如果容器是list,使用list::remove。如果容器是標(biāo)準(zhǔn)關(guān)聯(lián)容器,使用它的erase成員函數(shù)。
刪除容器中滿足某些條件的元素:
(2)如果容器是vector、string或者deque,使用erase-remove_if的慣用法。如果容器是list,使用list::remove_if。如果容器是標(biāo)準(zhǔn)關(guān)聯(lián)容器,使用remove_copy_if & swap 組合算法,或者自己協(xié)議個(gè)遍歷刪除算法。
參考資料:李健《編寫(xiě)高質(zhì)量C++代碼》第七章,用好STL這個(gè)大輪子。
一百四十一、auto關(guān)鍵字
一百四十二、程序中分配的地址都是邏輯地址,那有沒(méi)有辦法用一個(gè)指針指向一個(gè)物理地址呢?
一百四十三、inline函數(shù)必須在頭文件中定義嗎?
所謂內(nèi)聯(lián)函數(shù),就是編譯器將函數(shù)定義({…}之間的內(nèi)容)在函數(shù)調(diào)用處展開(kāi),藉此來(lái)免去函數(shù)調(diào)用的開(kāi)銷。
如果這個(gè)函數(shù)定義在頭文件中,所有include該頭文件的編譯單元都可以正確找到函數(shù)定義。然而,如果內(nèi)聯(lián)函數(shù)fun()定義在某個(gè)編譯單元A中,那么其他編譯單元中調(diào)用fun()的地方將無(wú)法解析該符號(hào),因?yàn)樵诰幾g單元A生成目標(biāo)文件A.obj后,內(nèi)聯(lián)函數(shù)fun()已經(jīng)被替換掉,A.obj中不再有fun這個(gè)符號(hào),鏈接器自然無(wú)法解析。
所以,如果一個(gè)inline函數(shù)會(huì)在多個(gè)源文件中被用到,那么必須把它定義在頭文件中。在C++中,這意味著如果inline函數(shù)具有public或者protected訪問(wèn)屬性,你就應(yīng)該這么做。
一百四十四、vector.clear() 函數(shù)
因?yàn)閷?duì)于 vector.clear() 并不真正釋放內(nèi)存(這是為優(yōu)化效率所做的事),clear實(shí)際所做的是為vector中所保存的所有對(duì)象調(diào)用析構(gòu)函數(shù)(如果有的話),然后初始化size這些東西,讓你覺(jué)得把所有的對(duì)象清除了。。。
真正釋放內(nèi)存是在vector的析構(gòu)函數(shù)里進(jìn)行的,所以一旦超出vector的作用域(如函數(shù)返回),首先它所保存的所有對(duì)象會(huì)被析構(gòu),然后會(huì)調(diào)用allocator中的deallocate函數(shù)回收對(duì)象本身的內(nèi)存。。。
所以你clear后還能訪問(wèn)到對(duì)象數(shù)據(jù)(因?yàn)樗緵](méi)清除),至于上面這位仁兄所指出的也有道理,在一些比較新的C++編譯器上(例如VS2008),當(dāng)進(jìn)行數(shù)組引用時(shí)(例如a[2]這種用法),STL庫(kù)中會(huì)有一些check函數(shù)根據(jù)當(dāng)前容器的size值來(lái)判斷下標(biāo)引用是否超出范圍,如果超出,則會(huì)執(zhí)行這樣一句:
_THROW(out_of_range, “invalid vector subscript”);
即拋出一個(gè)越界異常,你clear后沒(méi)有捕獲異常,程序在新編譯器編譯后就會(huì)崩潰掉。。。。
一百四十五、變參函數(shù)
一百四十六、能否實(shí)現(xiàn):函數(shù)指針作為參數(shù),但傳遞過(guò)去的函數(shù)不一樣
因?yàn)樵趯?xiě)項(xiàng)目的時(shí)候,完成了很多諸如,void recurs_GetId(logic_TreeNode *some,std::vector<int> & L); 的函數(shù),但是不具有一般性。現(xiàn)在希望完成一個(gè)函數(shù),void recurs_DoSth(); 可以傳遞進(jìn)一個(gè)簡(jiǎn)單操作的函數(shù),就可以完成任務(wù)?
一百四十七、宏函數(shù)可以有返回值嗎?
以下代碼在vs下無(wú)法編譯,未在gcc平臺(tái)編譯:
#include <iostream>#define KADDR(addr) / ({ int tmp = addr; / if (addr > 5)/ tmp = 2;/ else/ tmp = 3;/ (addr + tmp);/ })/ int main() { int addr = 4; int ans; ans = KADDR(addr); printf("%d./n", ans); addr = 8; ans = KADDR(addr); printf("%d./n", ans); return 0; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
輸出結(jié)果:7,10
上面的這段代碼定義了一個(gè)名叫KADDR的宏,它可以跟據(jù)輸入的addr數(shù)據(jù),對(duì)其進(jìn)行不同的偏移,但是最巧妙的是,這樣子寫(xiě)可以有把這個(gè)值返回到調(diào)用該宏的語(yǔ)句中。
一百四十八、net 命令
一百四十九、在程序中能夠使用指針獲取內(nèi)存的絕對(duì)物理地址嗎
一百五十、默認(rèn)參數(shù)是否只能在聲明處寫(xiě)
默認(rèn)參數(shù),在C++中,只要是函數(shù)都可以有默認(rèn)參數(shù),默認(rèn)參數(shù)是寫(xiě)在函數(shù)聲明里面的。
如:
void swap(int a = 10, int b= 20);//聲明//實(shí)現(xiàn) void swap(int a, int b) {... }- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
一百五十一、構(gòu)造函數(shù)會(huì)為對(duì)象分配空間嗎?
不會(huì),構(gòu)造函數(shù)是在已經(jīng)分配好的空間上初始化對(duì)象成員。分配空間是在new的時(shí)候運(yùn)行時(shí)分配的。
一百五十二、重載 new 時(shí),需要實(shí)現(xiàn)函數(shù)的構(gòu)造函數(shù)嗎?
這條跟 91 條有重合,重載new 會(huì)調(diào)用兩次構(gòu)造函數(shù)
(1)重載的成員函數(shù) new 里面只能::new其他的類型,不能new這個(gè)類本身。
(2)如果需要?jiǎng)?chuàng)建這個(gè)類本身的話,應(yīng)該要用malloc, malloc在分配完內(nèi)存后,并不會(huì)初始化。
可能跟 placement new 有關(guān)。
一百五十三、placement new
一百五十四、debug 和 release 的區(qū)別,為什么有時(shí) debug 可以跑,但是 release 下崩潰?
一百五十五、VC編譯選項(xiàng) /ML /MLd /MT /MTd /MD /MDd之間的區(qū)別
一百五十六、內(nèi)存斷點(diǎn) && 條件斷點(diǎn)
一百五十七、c++重載運(yùn)算符
一百五十八、A* 算法
一百五十九、c++流
一百六十、maze && 八皇后 — 回溯 && 深搜 && 廣搜
http://blog.csdn.net/K346K346/article/details/51289478
一百六十一、函數(shù)指針作為參數(shù),可以接收簽名完全不同(參數(shù)個(gè)數(shù)、類型都不定)的函數(shù)地址嗎?
一百六十二、參數(shù)個(gè)數(shù)不定的函數(shù)(類似 printf)
http://www.cnblogs.com/VRS_technology/archive/2010/05/10/1732006.html
一百六十三、類成員變量定義為引用,注意事項(xiàng)
http://blog.csdn.net/aore2010/article/details/5870928
一百六十四、multimap 允許 key 相同
適用于多對(duì)一關(guān)系
一百六十五、Qt 資源
http://download.qt.io/
一百六十六、實(shí)時(shí)傳輸協(xié)議 RTP
一百六十七、c++ 復(fù)合數(shù)據(jù)類型
一百六十八、c++ 如何實(shí)現(xiàn)一個(gè)無(wú)法被繼承的類
一百六十九、二叉排序樹(shù) BST
一百七十、KMP
一百七十一、TCP的流量控制和擁塞控制
一百七十二、TSP 旅行商問(wèn)題(dp + 遞歸)
一百七十三、如何使經(jīng)過(guò)指定節(jié)點(diǎn)集的路徑最短
一百七十四、c++中的函數(shù)重載、隱藏、覆蓋、重寫(xiě)的區(qū)別
一百七十五、卡特蘭數(shù)
一百七十六、電子郵件協(xié)議以及工作原理
一百七十七、注冊(cè)表詳解
一百七十八、setjmp longjmp
一百七十九、千萬(wàn)不要重載 || &&
一百八十、c++對(duì)象模型 && 內(nèi)存布局
一百八十一、守護(hù)進(jìn)程
一百八十二、虛調(diào)用
一百八十三、c++為什么不加入垃圾回收?
一百八十四、main 函數(shù)參數(shù)中字符數(shù)組指向的空間在哪
https://www.quora.com/In-C-the-main-function-takes-a-pointer-to-an-integer-and-a-pointer-to-a-pointer-to-a-char-To-where-does-the-latter-point
一百八十五、進(jìn)程 vs. 線程
http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/001397567993007df355a3394da48f0bf14960f0c78753f000
一百八十六、HTTP 400/401/403/404/500 網(wǎng)頁(yè)錯(cuò)誤代碼
http://blog.csdn.net/stuartjing/article/details/7579427
一百八十七、環(huán)境變量
一百八十八、include 命令包含頭文件時(shí),會(huì)不會(huì)包含頭文件過(guò)多,生成空間過(guò)大
一百八十九、nginx
一百九十、4K對(duì)齊
一百九十一、C++中POD類型
一百九十二、預(yù)編譯指令 #pragma
一百九十三、賦值語(yǔ)句返回值
http://blog.csdn.net/jackbai1990/article/details/7467030
賦值語(yǔ)句的返回值是所賦的值,于是在C/C++中,就可以有如下的連續(xù)賦值語(yǔ)句:
b = a = 10;- 1
- 1
一百九十四、SYN Flood攻擊
一百九十五、Java學(xué)習(xí)計(jì)劃(不斷給更新)
一百九十六、Java反射機(jī)制
什么是反射
一般在開(kāi)發(fā)針對(duì)java語(yǔ)言相關(guān)的開(kāi)發(fā)工具和框架時(shí)使用,比如根據(jù)某個(gè)類的函數(shù)名字,然后執(zhí)行函數(shù),實(shí)現(xiàn)類的動(dòng)態(tài)調(diào)用!
反射實(shí)例:
package test;import java.lang.reflect.*;/*** 基類Animal*/ class Animal {public Animal() {}public int location;protected int age;private int height;int length;public int getAge() {return age;}public void setAge(int age) {this.age = age;}private int getHeight() {return height;}public void setHeight(int height) {this.height = height;}}/*** 子類 —— Dog*/ class Dog extends Animal {public Dog() {}public String color;protected String name;private String type;String fur;}public class test {public static void main(String[] args) {System.out.println("Hello World!");testRefect();}private static void testRefect() {try {//返回類中的任何可見(jiàn)性的屬性(不包括基類)System.out.println("Declared fileds: ");Field[] fields = Dog.class.getDeclaredFields();for (int i = 0; i < fields.length; i++) {System.out.println(fields[i].getName());}//獲得類中指定的public屬性(包括基類)System.out.println("public fields: ");fields = Dog.class.getFields();for (int i = 0; i < fields.length; i++) {System.out.println(fields[i].getName());}//getMethod()只能調(diào)用共有方法,不能反射調(diào)用私有方法Dog dog = new Dog();dog.setAge(1);Method method1 = dog.getClass().getMethod("getAge", null);Object value = method1.invoke(dog);System.out.println("age: " + value);//調(diào)用基類的private類型方法/**先實(shí)例化一個(gè)Animal的對(duì)象 */Animal animal = new Animal();Class a = animal.getClass();//Animal中g(shù)etHeight方法是私有方法,只能使用getDeclaredMethodMethod method2 = a.getDeclaredMethod("getHeight", null);method2.setAccessible(true);//java反射無(wú)法傳入基本類型變量,可以通過(guò)如下形式int param = 12;Class[] argsClass = new Class[] { int.class };//Animal中g(shù)etHeight方法是共有方法,可以使用getMethodMethod method3 = a.getMethod("setHeight", argsClass);method3.invoke(animal, param);//Animal中height變量如果聲明為static變量,這樣在重新實(shí)例化一個(gè)Animal對(duì)象后調(diào)用getHeight(),還可以讀到height的值int height = (Integer) method2.invoke(animal);System.out.println("height: " + height);/**不用先實(shí)例化一個(gè)Animal,直接通過(guò)反射來(lái)獲得animal的class對(duì)象*/Class anotherAnimal = Class.forName("test.Animal");//Animal中g(shù)etHeight方法是私有方法,只能使用getDeclaredMethodMethod method4 = anotherAnimal.getDeclaredMethod("getHeight", null);method4.setAccessible(true);//java反射無(wú)法傳入基本類型變量,可以通過(guò)如下形式int param2 = 15;Class[] argsClass2 = new Class[] { int.class };//Animal中setHeight方法是共有方法,可以使用getMethodMethod method5 = anotherAnimal.getMethod("setHeight", argsClass2);method5.invoke(anotherAnimal.newInstance(), param2);//Animal中height變量必須聲明為static變量,這樣在重新實(shí)例化一個(gè)Animal對(duì)象后調(diào)用getHeight()才能讀到height的值// 否則重新實(shí)例化一個(gè)新的Animal對(duì)象,讀到的值為初始值int height2 = (Integer) method4.invoke(anotherAnimal.newInstance());System.out.println("height:" + height2);} catch (NoSuchMethodException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();}}}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
詳見(jiàn):http://blog.csdn.net/scythe666/article/details/51704809
一百九十七、C++反射機(jī)制
C++原生不支持反射機(jī)制,但是可以手動(dòng)實(shí)現(xiàn):
#include <map> #include <iostream> #include <string> using namespace std;typedef void* (*PTRCreateObject)(void); class ClassFactory{ private: map<string, PTRCreateObject> m_classMap ; ClassFactory(){}; //構(gòu)造函數(shù)私有化public: void* getClassByName(string className); void registClass(string name, PTRCreateObject method) ; static ClassFactory& getInstance() ; };void* ClassFactory::getClassByName(string className){ map<string, PTRCreateObject>::const_iterator iter; iter = m_classMap.find(className) ; if ( iter == m_classMap.end() ) return NULL ; else return iter->second() ; } void ClassFactory::registClass(string name, PTRCreateObject method){ m_classMap.insert(pair<string, PTRCreateObject>(name, method)) ; } ClassFactory& ClassFactory::getInstance(){static ClassFactory sLo_factory; return sLo_factory ; } class RegisterAction{ public:RegisterAction(string className,PTRCreateObject ptrCreateFn){ClassFactory::getInstance().registClass(className,ptrCreateFn);} };#define REGISTER(className) \className* objectCreator##className(){ \return new className; \} \RegisterAction g_creatorRegister##className( \#className,(PTRCreateObject)objectCreator##className)//test class class TestClass{ public:void m_print(){cout<<"hello TestClass"<<endl;}; }; REGISTER(TestClass);int main(int argc,char* argv[]){TestClass* ptrObj=(TestClass*)ClassFactory::getInstance().getClassByName("TestClass");ptrObj->m_print(); }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
詳見(jiàn):http://blog.csdn.net/scythe666/article/details/51718864
一百九十八、JVM內(nèi)存模型
JVM內(nèi)存模型分區(qū)見(jiàn)下圖:
(1)方法區(qū):用于存儲(chǔ)已被虛擬機(jī)加載的類信息、常量、靜態(tài)變量、即時(shí)編譯器編譯后的代碼等數(shù)據(jù)。對(duì)于習(xí)慣在HotSpot 虛擬機(jī)上開(kāi)發(fā)和部署程序的開(kāi)發(fā)者來(lái)說(shuō),很多人愿意把方法區(qū)稱為“永久代”(Permanent Generation),本質(zhì)上兩者并不等價(jià)。
(2)堆區(qū):Java 堆是被所有線程共享的一塊內(nèi)存區(qū)域,在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建。此內(nèi)存區(qū)域的唯一目的就是存放對(duì)象實(shí)例,幾乎所有的對(duì)象實(shí)例都在這里分配內(nèi)存。由于逃逸分析等分析或優(yōu)化技術(shù),所有的對(duì)象都分配在堆上也漸漸變得不是那么“絕對(duì)”了。
Java 堆是垃圾收集器管理的主要區(qū)域,因此很多時(shí)候也被稱做“GC 堆”
(3)棧區(qū):與程序計(jì)數(shù)器一樣,Java 虛擬機(jī)棧(Java Virtual Machine Stacks)也是線程私有的,它的生命周期與線程相同。棧中主要存放一些基本類型的變量(,int, short, long, byte, float,double, boolean, char)和對(duì)象句柄。
(4)程序計(jì)數(shù)器:程序計(jì)數(shù)器(Program Counter Register)是一塊較小的內(nèi)存空間,它的作用可以看做是當(dāng)前線程所執(zhí)行的字節(jié)碼的行號(hào)指示器。
由于Java虛擬機(jī)的多線程是通過(guò)線程輪流切換并分配處理器執(zhí)行時(shí)間的方式來(lái)實(shí)現(xiàn)的,在任何一個(gè)確定的時(shí)刻,一個(gè)處理器(對(duì)于多核處理器來(lái)說(shuō)是一個(gè)內(nèi)核)只會(huì)執(zhí)行一條線程中的指令。因此,為了線程切換后能恢復(fù)到正確的執(zhí)行位置,每條線程都需要有一個(gè)獨(dú)立的程序計(jì)數(shù)器,各條線程之間的計(jì)數(shù)器互不影響,獨(dú)立存儲(chǔ),我們稱這類內(nèi)存區(qū)域?yàn)椤?strong>線程私有”的內(nèi)存。
(5)本地方法棧:本地方法棧(Native Method Stacks)與虛擬機(jī)棧所發(fā)揮的作用是非常相似的,其區(qū)別不過(guò)是虛擬機(jī)棧為虛擬機(jī)執(zhí)行Java 方法(也就是字節(jié)碼)服務(wù),而本地方法棧則是為虛擬機(jī)使用到的Native 方法服務(wù)。
詳見(jiàn):http://blog.csdn.net/scythe666/article/details/51700142
一百久十久、阻塞VS非阻塞,同步VS異步
同步異步是針對(duì)整個(gè)IO的過(guò)程,阻塞非阻塞是針對(duì)單次操作
用很貼切的比喻來(lái)說(shuō)明同步異步:
回調(diào)的比喻:A委托B做事,但是B現(xiàn)在忙,于是A告訴B如何去做,A就回去了,B做完手頭事情后把A的事情做完了
通知的比喻:水壺?zé)?#xff0c;如果一直看著水壺,是否冒煙,就是同步
如果燒好水壺響了才去管就是異步。
同步異步是一種動(dòng)作,阻塞和非阻塞是一種狀態(tài)
1、同步和異步是針對(duì)應(yīng)用程序和內(nèi)核的交互而言的。
(1)同步:用戶進(jìn)程觸發(fā)IO操作并等待或者輪詢的去查看IO操作是否就緒;
(2)異步:用戶進(jìn)程觸發(fā)IO操作以后便開(kāi)始做自己的事情,而當(dāng)IO操作已經(jīng)完成的時(shí)候會(huì)得到IO完成的通知(異步的特點(diǎn)就是通知)。
2、阻塞和非阻塞是針對(duì)于進(jìn)程在訪問(wèn)數(shù)據(jù)的時(shí)候,根據(jù)IO操作的就緒狀態(tài)來(lái)采取的不同方式,說(shuō)白了是一種讀取或者寫(xiě)入操作函數(shù)的實(shí)現(xiàn)方式
(1)阻塞方式下讀取或者寫(xiě)入函數(shù)將一直等待
(2)非阻塞方式下,讀取或者寫(xiě)入函數(shù)會(huì)立即返回一個(gè)狀態(tài)值。
一般來(lái)說(shuō)I/O模型可以分為:同步阻塞,同步非阻塞,異步阻塞,異步非阻塞IO
(1)同步阻塞IO:
在此種方式下,用戶進(jìn)程在發(fā)起一個(gè)IO操作以后,必須等待IO操作的完成,只有當(dāng)真正完成了IO操作以后,用戶進(jìn)程才能運(yùn)行。JAVA傳統(tǒng)的IO模型屬于此種方式!
(2)同步非阻塞IO:
在此種方式下,用戶進(jìn)程發(fā)起一個(gè)IO操作以后邊可返回做其它事情,但是用戶進(jìn)程需要時(shí)不時(shí)的詢問(wèn)IO操作是否就緒,這就要求用戶進(jìn)程不停的去詢問(wèn),從而引入不必要的CPU資源浪費(fèi)。其中目前JAVA的NIO就屬于同步非阻塞IO。
(3)異步阻塞IO:
此種方式下是指應(yīng)用發(fā)起一個(gè)IO操作以后,不等待內(nèi)核IO操作的完成,等內(nèi)核完成IO操作以后會(huì)通知應(yīng)用程序,這其實(shí)就是同步和異步最關(guān)鍵的區(qū)別,同步必須等待或者主動(dòng)的去詢問(wèn)IO是否完成,那么為什么說(shuō)是阻塞的呢?因?yàn)榇藭r(shí)是通過(guò)select系統(tǒng)調(diào)用來(lái)完成的,而select函數(shù)本身的實(shí)現(xiàn)方式是阻塞的,而采用select函數(shù)有個(gè)好處就是它可以同時(shí)監(jiān)聽(tīng)多個(gè)文件句柄(如果從UNP的角度看,select屬于同步操作。因?yàn)閟elect之后,進(jìn)程還需要讀寫(xiě)數(shù)據(jù)),從而提高系統(tǒng)的并發(fā)性!
(4)異步非阻塞IO:
在此種模式下,用戶進(jìn)程只需要發(fā)起一個(gè)IO操作然后立即返回,等IO操作真正的完成以后,應(yīng)用程序會(huì)得到IO操作完成的通知,此時(shí)用戶進(jìn)程只需要對(duì)數(shù)據(jù)進(jìn)行處理就好了,不需要進(jìn)行實(shí)際的IO讀寫(xiě)操作,因?yàn)檎嬲腎O讀取或者寫(xiě)入操作已經(jīng)由內(nèi)核完成了。目前Java中還沒(méi)有支持此種IO模型。
(其實(shí)阻塞與非阻塞都可以理解為同步范疇下才有的概念,對(duì)于異步,就不會(huì)再去分阻塞非阻塞。對(duì)于用戶進(jìn)程,接到異步通知后,就直接操作進(jìn)程用戶態(tài)空間里的數(shù)據(jù)好了。)
詳見(jiàn):http://blog.csdn.net/scythe666/article/details/51701360
二百、高性能IO設(shè)計(jì)的Reactor和Proactor模式
首先來(lái)看看Reactor模式,Reactor模式應(yīng)用于同步I/O的場(chǎng)景。我們分別以讀操作和寫(xiě)操作為例來(lái)看看Reactor中的具體步驟:
讀取操作:
1. 應(yīng)用程序注冊(cè)讀就緒事件和相關(guān)聯(lián)的事件處理器
2. 事件分離器等待事件的發(fā)生
3. 當(dāng)發(fā)生讀就緒事件的時(shí)候,事件分離器調(diào)用第一步注冊(cè)的事件處理器
4. 事件處理器首先執(zhí)行實(shí)際的讀取操作,然后根據(jù)讀取到的內(nèi)容進(jìn)行進(jìn)一步的處理
寫(xiě)入操作類似于讀取操作,只不過(guò)第一步注冊(cè)的是寫(xiě)就緒事件。
下面我們來(lái)看看Proactor模式中讀取操作和寫(xiě)入操作的過(guò)程:
讀取操作:
1. 應(yīng)用程序初始化一個(gè)異步讀取操作,然后注冊(cè)相應(yīng)的事件處理器,此時(shí)事件處理器不關(guān)注讀取就緒事件,而是關(guān)注讀取完成事件,這是區(qū)別于Reactor的關(guān)鍵。
2. 事件分離器等待讀取操作完成事件
3. 在事件分離器等待讀取操作完成的時(shí)候,操作系統(tǒng)調(diào)用內(nèi)核線程完成讀取操作(異步IO都是操作系統(tǒng)負(fù)責(zé)將數(shù)據(jù)讀寫(xiě)到應(yīng)用傳遞進(jìn)來(lái)的緩沖區(qū)供應(yīng)用程序操作,操作系統(tǒng)扮演了重要角色),并將讀取的內(nèi)容放入用戶傳遞過(guò)來(lái)的緩存區(qū)中。這也是區(qū)別于Reactor的一點(diǎn),Proactor中,應(yīng)用程序需要傳遞緩存區(qū)。
4. 事件分離器捕獲到讀取完成事件后,激活應(yīng)用程序注冊(cè)的事件處理器,事件處理器直接從緩存區(qū)讀取數(shù)據(jù),而不需要進(jìn)行實(shí)際的讀取操作。
Proactor中寫(xiě)入操作和讀取操作,只不過(guò)感興趣的事件是寫(xiě)入完成事件。
從上面可以看出,Reactor和Proactor模式的主要區(qū)別就是真正的讀取和寫(xiě)入操作是有誰(shuí)來(lái)完成的,Reactor中需要應(yīng)用程序自己讀取或者寫(xiě)入數(shù)據(jù),而Proactor模式中,應(yīng)用程序不需要進(jìn)行實(shí)際的讀寫(xiě)過(guò)程,它只需要從緩存區(qū)讀取或者寫(xiě)入即可,操作系統(tǒng)會(huì)讀取緩存區(qū)或者寫(xiě)入緩存區(qū)到真正的IO設(shè)備.
綜上所述,同步和異步是相對(duì)于應(yīng)用和內(nèi)核的交互方式而言的,同步 需要主動(dòng)去詢問(wèn),而異步的時(shí)候內(nèi)核在IO事件發(fā)生的時(shí)候通知應(yīng)用程序,而阻塞和非阻塞僅僅是系統(tǒng)在調(diào)用系統(tǒng)調(diào)用的時(shí)候函數(shù)的實(shí)現(xiàn)方式而已。
詳見(jiàn):https://segmentfault.com/a/1190000002715832
二百零一、秒懂樂(lè)觀鎖和悲觀鎖
悲觀鎖(Pessimistic Lock), 顧名思義,就是很悲觀,每次去拿數(shù)據(jù)的時(shí)候都認(rèn)為別人會(huì)修改,所以每次在拿數(shù)據(jù)的時(shí)候都會(huì)上鎖,這樣別人想拿這個(gè)數(shù)據(jù)就會(huì)block直到它拿到鎖。傳統(tǒng)的關(guān)系型數(shù)據(jù)庫(kù)里邊就用到了很多這種鎖機(jī)制,比如行鎖,表鎖等,讀鎖,寫(xiě)鎖等,都是在做操作之前先上鎖。
樂(lè)觀鎖(Optimistic Lock), 顧名思義,就是很樂(lè)觀,每次去拿數(shù)據(jù)的時(shí)候都認(rèn)為別人不會(huì)修改,所以不會(huì)上鎖,但是在更新的時(shí)候會(huì)判斷一下在此期間別人有沒(méi)有去更新這個(gè)數(shù)據(jù),可以使用版本號(hào)等機(jī)制。樂(lè)觀鎖適用于多讀的應(yīng)用類型,這樣可以提高吞吐量,像數(shù)據(jù)庫(kù)如果提供類似于write_condition機(jī)制的其實(shí)都是提供的樂(lè)觀鎖。
兩種鎖各有優(yōu)缺點(diǎn),不可認(rèn)為一種好于另一種,像樂(lè)觀鎖適用于寫(xiě)比較少的情況下,即沖突真的很少發(fā)生的時(shí)候,這樣可以省去了鎖的開(kāi)銷,加大了系統(tǒng)的整個(gè)吞吐量。但如果經(jīng)常產(chǎn)生沖突,上層應(yīng)用會(huì)不斷的進(jìn)行retry,這樣反倒是降低了性能,所以這種情況下用悲觀鎖就比較合適。
原文:http://blog.csdn.net/hongchangfirst/article/details/26004335
二百零二、序列化和反序列化
1、什么是序列化
序列化(Serialization)是將對(duì)象的狀態(tài)信息轉(zhuǎn)換為可以存儲(chǔ)或傳輸?shù)男问降倪^(guò)程。在序列化期間,對(duì)象將其當(dāng)前狀態(tài)寫(xiě)入到臨時(shí)或持久性存儲(chǔ)區(qū)。之后可以通過(guò)從存儲(chǔ)區(qū)中讀取或反序列化對(duì)象的狀態(tài),重新創(chuàng)建該對(duì)象。
也可以理解為:將對(duì)象轉(zhuǎn)換為容易傳輸?shù)母袷降倪^(guò)程。例如,可以序列化一個(gè)對(duì)象,然后使用 HTTP 通過(guò) Internet 在客戶端和服務(wù)器之間傳輸該對(duì)象。在另一端,反序列化將從該流重新構(gòu)造對(duì)象。
2、Java序列化的實(shí)現(xiàn)
序列化的實(shí)現(xiàn):將需要被序列化的類實(shí)現(xiàn)Serializable接口,該接口沒(méi)有需要實(shí)現(xiàn)的方法,implements Serializable只是為了標(biāo)注該對(duì)象是可被序列化的,然后使用一個(gè)輸出流(如:FileOutputStream)來(lái)構(gòu)造一個(gè)ObjectOutputStream(對(duì)象流)對(duì)象,接著,使用ObjectOutputStream對(duì)象的writeObject(Object obj)方法就可以將參數(shù)為obj的對(duì)象寫(xiě)出(即保存其狀態(tài)),要恢復(fù)的話則用輸入流
3、什么時(shí)候使用序列化
(1)對(duì)象序列化可以實(shí)現(xiàn)分布式對(duì)象。主要應(yīng)用例如:RMI要利用對(duì)象序列化運(yùn)行遠(yuǎn)程主機(jī)上的服務(wù),就像在本地機(jī)上運(yùn)行對(duì)象時(shí)一樣。
(2)java對(duì)象序列化不僅保留一個(gè)對(duì)象的數(shù)據(jù),而且遞歸保存對(duì)象引用的每個(gè)對(duì)象的數(shù)據(jù)。可以將整個(gè)對(duì)象層次寫(xiě)入字節(jié)流中,可以保存在文件中或在網(wǎng)絡(luò)連接上傳遞。利用對(duì)象序列化可以進(jìn)行對(duì)象的”深復(fù)制”,即復(fù)制對(duì)象本身及引用的對(duì)象本身。序列化一個(gè)對(duì)象可能得到整個(gè)對(duì)象序列。
二百零三、關(guān)于RPC
首先了解什么叫RPC,為什么要RPC,RPC是指遠(yuǎn)程過(guò)程調(diào)用,也就是說(shuō)兩臺(tái)服務(wù)器A,B,一個(gè)應(yīng)用部署在A服務(wù)器上,想要調(diào)用B服務(wù)器上應(yīng)用提供的函數(shù)/方法,由于不在一個(gè)內(nèi)存空間,不能直接調(diào)用,需要通過(guò)網(wǎng)絡(luò)來(lái)表達(dá)調(diào)用的語(yǔ)義和傳達(dá)調(diào)用的數(shù)據(jù)。
詳見(jiàn):http://blog.csdn.net/scythe666/article/details/51719408
二百零四、非阻塞同步算法與CAS(Compare and Swap)無(wú)鎖算法
要實(shí)現(xiàn)無(wú)鎖(lock-free)的非阻塞算法有多種實(shí)現(xiàn)方法,其中CAS(比較與交換,Compare and swap)是一種有名的無(wú)鎖算法。CAS, CPU指令,在大多數(shù)處理器架構(gòu),包括IA32、Space中采用的都是CAS指令,CAS的語(yǔ)義是“我認(rèn)為V的值應(yīng)該為A,如果是,那么將V的值更新為B,否則不修改并告訴V的值實(shí)際為多少”,CAS是項(xiàng)樂(lè)觀鎖技術(shù),當(dāng)多個(gè)線程嘗試使用CAS同時(shí)更新同一個(gè)變量時(shí),只有其中一個(gè)線程能更新變量的值,而其它線程都失敗,失敗的線程并不會(huì)被掛起,而是被告知這次競(jìng)爭(zhēng)中失敗,并可以再次嘗試。CAS有3個(gè)操作數(shù),內(nèi)存值V,舊的預(yù)期值A(chǔ),要修改的新值B。當(dāng)且僅當(dāng)預(yù)期值A(chǔ)和內(nèi)存值V相同時(shí),將內(nèi)存值V修改為B,否則什么都不做。CAS無(wú)鎖算法的C實(shí)現(xiàn)如下:
int compare_and_swap (int* reg, int oldval, int newval) {ATOMIC();int old_reg_val = *reg;if (old_reg_val == oldval) *reg = newval;END_ATOMIC();return old_reg_val; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
CAS比較與交換的偽代碼可以表示為:
do{ 備份舊數(shù)據(jù); 基于舊數(shù)據(jù)構(gòu)造新數(shù)據(jù); }while(!CAS( 內(nèi)存地址,備份的舊數(shù)據(jù),新數(shù)據(jù) ))- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
(上圖的解釋:CPU去更新一個(gè)值,但如果想改的值不再是原來(lái)的值,操作就失敗,因?yàn)楹苊黠@,有其它操作先改變了這個(gè)值。)
就是指當(dāng)兩者進(jìn)行比較時(shí),如果相等,則證明共享數(shù)據(jù)沒(méi)有被修改,替換成新值,然后繼續(xù)往下運(yùn)行;如果不相等,說(shuō)明共享數(shù)據(jù)已經(jīng)被修改,放棄已經(jīng)所做的操作,然后重新執(zhí)行剛才的操作。容易看出 CAS 操作是基于共享數(shù)據(jù)不會(huì)被修改的假設(shè),采用了類似于數(shù)據(jù)庫(kù)的 commit-retry 的模式。當(dāng)同步?jīng)_突出現(xiàn)的機(jī)會(huì)很少時(shí),這種假設(shè)能帶來(lái)較大的性能提升。
詳見(jiàn):http://www.cnblogs.com/Mainz/p/3546347.html?utm_source=tuicool&utm_medium=referral
二百零五、spring框架學(xué)習(xí)
基本學(xué)習(xí)Java,spring是必學(xué)的,這個(gè)框架是Java集大成者,活用各種Java特性和設(shè)計(jì)模式,實(shí)在是牛逼的不行,如果可以的話最好讀源碼。
詳見(jiàn):http://blog.csdn.net/scythe666/article/details/51706041
二百零六、static塊的本質(zhì)
Java靜態(tài)變量的初始化
詳見(jiàn):http://blog.csdn.net/darxin/article/details/5293427
二百零七、Java的override注解寫(xiě)與不寫(xiě)
/*Java 中的覆蓋@Override注解 寫(xiě)與不寫(xiě)的一點(diǎn)點(diǎn)理解一般來(lái)說(shuō),寫(xiě)與不寫(xiě)沒(méi)什么區(qū)別,JVM可以自識(shí)別寫(xiě)的情況下:即說(shuō)明子類要覆蓋基類的方法,基類必須存在方法(控制類型public,protected,返回值,參數(shù)列表類型)與子類方法完成一致的方法,否則會(huì)報(bào)錯(cuò)(找不到被Override的方法)。在不寫(xiě)@Override注解的情況下,當(dāng)基類存在與子類各種條件都符合的方法是即實(shí)現(xiàn)覆蓋;如果條件不符合時(shí),則是當(dāng)成新定義的方法使用。所以如果想覆蓋基類方法時(shí),最好還是寫(xiě)上@Override注解,這樣有利于編譯器幫助檢查錯(cuò)誤 */public class OverrideTest extends Test{@Override//此處寫(xiě)與不寫(xiě)都能覆蓋基類的t(String)方法public void t(String s){System.out.println("OverrideTest.t(String):" + s);}//此處不能寫(xiě)@Override注解,因?yàn)榉椒▍?shù)類型與基類的t2方法的參數(shù)類型不同//所以此處只能新定義了一個(gè)t2(float)方法,并不能實(shí)現(xiàn)覆蓋public void t2(float f){System.out.println("OverrideTest.t2(float):" + f);}public static void main(String[] args){OverrideTest ot = new OverrideTest();ot.t("china34420");ot.t2(1.0f);ot.t2(1);ot.t3();} } /*輸出:OverrideTest.t(String):china34420OverrideTest.t2(float):1.0Test.t2(int):1OverrideTest.t(String):override */class Test{public void t(String s){System.out.println("Test.t(String):" + s);}public void t2(int i){System.out.println("Test.t2(int):" + i); }public void t3(){t("override"); } }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
二百零八、進(jìn)程VS端口
一個(gè)進(jìn)程可以監(jiān)聽(tīng)多個(gè)端口
nginx可以配置多個(gè)server,每個(gè)server監(jiān)聽(tīng)不同的端口.
PHP-fpm可以配置多個(gè)pool,每個(gè)pool監(jiān)聽(tīng)不同的端口.
httpd可以用Listen監(jiān)聽(tīng)多個(gè)端口(Listen監(jiān)聽(tīng)了這些端口,VirtualHost里才能使用這些端口)
二百零九、有用過(guò)Linux中的epoll嗎?它的作用是什么?
答:
epoll是linux內(nèi)核為處理大批量文件描述符而作了改進(jìn)的poll,是Linux下多路復(fù)用IO接口select/poll的增強(qiáng)版本,它能顯著提高程序在大量并發(fā)連接中只有少量活躍的情況下的系統(tǒng)CPU利用率。
二百一十、epoll和select的區(qū)別在哪,或者說(shuō)優(yōu)勢(shì)在哪?
答:
(1)epoll除了提供select/poll那種IO事件的水平觸發(fā)(Level Triggered)外,還提供了邊緣觸發(fā)(Edge Triggered);
(2)select的句柄數(shù)目受限,在linux/posix_types.h頭文件有這樣的聲明:#define __FD_SETSIZE 1024,表示select最多同時(shí)監(jiān)聽(tīng)1024個(gè)fd。而epoll沒(méi)有,epoll的最大并發(fā)的連接數(shù)的理論值無(wú)上限,但由于實(shí)際內(nèi)存資源有限,實(shí)際并發(fā)的連接數(shù)受到資源的限制和最大的打開(kāi)文件句柄數(shù)目的限制;
(3)epoll的最大好處是不會(huì)隨著FD的數(shù)目增長(zhǎng)而降低效率,在selec中采用輪詢處理,其中的數(shù)據(jù)結(jié)構(gòu)類似一個(gè)數(shù)組的數(shù)據(jù)結(jié)構(gòu),而epoll 是維護(hù)一個(gè)隊(duì)列,直接看隊(duì)列是不是空就可以了。
(4)使用mmap加速內(nèi)核與用戶空間的消息傳遞。無(wú)論是select,poll還是epoll都需要內(nèi)核把FD消息通知給用戶空間,如何避免不必要的內(nèi)存拷貝就很重要,在這點(diǎn)上,epoll是通過(guò)內(nèi)核于用戶空間mmap同一塊內(nèi)存實(shí)現(xiàn)的。
此外,epoll創(chuàng)建時(shí)傳入的參數(shù)是什么?
epoll對(duì)象可通過(guò)int epoll_create(int size)來(lái)創(chuàng)建一個(gè)epoll的實(shí)例,size用來(lái)告訴內(nèi)核這個(gè)監(jiān)聽(tīng)的數(shù)目一共有多大。這個(gè)參數(shù)不同于select()中的第一個(gè)參數(shù),給出最大監(jiān)聽(tīng)的fd+1的值。需要注意的是,當(dāng)創(chuàng)建好epoll句柄后,它就是會(huì)占用一個(gè)fd值。所以在使用完epoll后,必須調(diào)用close()關(guān)閉,否則可能導(dǎo)致fd被耗盡。但是自從linux2.6.8之后,size參數(shù)是被忽略的。
此外,創(chuàng)建epoll實(shí)例,還可以通過(guò)int epoll_create1(int flags)。
這個(gè)函數(shù)是在linux 2.6.27中加入的,其實(shí)它和epoll_create差不多,不同的是epoll_create1函數(shù)的參數(shù)是flags,當(dāng)flag是0時(shí),表示和epoll_create函數(shù)完全一樣,不需要size的提示了。
當(dāng)flag = EPOLL_CLOEXEC,創(chuàng)建的epfd會(huì)設(shè)置FD_CLOEXEC;
當(dāng)flag = EPOLL_NONBLOCK,創(chuàng)建的epfd會(huì)設(shè)置為非阻塞。
一般用法都是使用EPOLL_CLOEXEC。關(guān)于EPOLL_CLOEXEC,網(wǎng)上資料說(shuō)明是對(duì)epfd的一個(gè)標(biāo)識(shí)說(shuō)明,用來(lái)設(shè)置文件close-on-exec狀態(tài)的。當(dāng)close-on-exec狀態(tài)為0時(shí),調(diào)用exec時(shí),fd不會(huì)被關(guān)閉;狀態(tài)非零時(shí)則會(huì)被關(guān)閉,這樣做可以防止fd泄露給執(zhí)行exec后的進(jìn)程。關(guān)于exec的用法,大家可以去自己查閱下,或者直接man exec。
二百一十二、寫(xiě)出一個(gè)程序,讓CPU成正弦曲線
http://www.cnblogs.com/matrix-r/p/3246838.html
二百一十三、什么是編程語(yǔ)言的自舉?
就是自己的編譯器可以自行編譯自己的編譯器。
實(shí)現(xiàn)方法就是這個(gè)編譯器的作者用這個(gè)語(yǔ)言的一些特性來(lái)編寫(xiě)編譯器并在該編譯器中支持這些自己使用到的特性。
首先,第一個(gè)編譯器肯定是用別的語(yǔ)言寫(xiě)的(不論是C還是Go還是Lisp還是Python),后面的版本才能談及自舉。
至于先有雞還是先有蛋,我可以舉個(gè)這樣的不太恰當(dāng)?shù)睦?#xff1a;比如我寫(xiě)了一個(gè)可以自舉的C編譯器叫作mycc,不論是編譯器本身的執(zhí)行效率還是生成的代碼的質(zhì)量都遠(yuǎn)遠(yuǎn)好于gcc(本故事純屬虛構(gòu)),但我用的都是標(biāo)準(zhǔn)的C寫(xiě)的,那么我可以就直接用gcc編譯mycc的源碼,得到一份可以生成高質(zhì)量代碼但本身執(zhí)行效率低下的mycc,然后當(dāng)然如果我再用這個(gè)生成的mycc編譯mycc的源碼得到新的一份mycc,新的這份不光會(huì)產(chǎn)生和原來(lái)那份同等高質(zhì)量的代碼,而且還能擁有比先前版本更高的執(zhí)行效率(因?yàn)榍耙环菔莋cc的編譯產(chǎn)物,后一份是mycc的編譯產(chǎn)物,而mycc生成的代碼質(zhì)量要遠(yuǎn)好于gcc的)。故事雖然是虛構(gòu)的,但是道理差不多就是這么個(gè)道理。這也就是為什么如果從源碼編譯安裝新版本的gcc的話,往往會(huì)“編譯——安裝”兩到三遍的原因。
二百一十四、內(nèi)存為什么要分頁(yè)
假設(shè)內(nèi)存是連續(xù)分配的(也就是程序在物理內(nèi)存上是連續(xù)的)
1.進(jìn)程A進(jìn)來(lái),向os申請(qǐng)了200的內(nèi)存空間,于是os把0~199分配給A
2.進(jìn)程B進(jìn)來(lái),向os申請(qǐng)了5的內(nèi)存空間,os把200~204分配給它
3.進(jìn)程C進(jìn)來(lái),向os申請(qǐng)了100的內(nèi)存空間,os把205~304分配給它
4.這個(gè)時(shí)候進(jìn)程B運(yùn)行完了,把200~204還給os
但是很長(zhǎng)時(shí)間以后,只要系統(tǒng)中的出現(xiàn)的進(jìn)程的大小>5的話,200~204這段空間都不會(huì)被分配出去(只要A和C不退出)。
過(guò)了一段更長(zhǎng)的時(shí)間,內(nèi)存中就會(huì)出現(xiàn)許許多多200~204這樣不能被利用的碎片……
而分頁(yè)機(jī)制讓程序可以在邏輯上連續(xù)、物理上離散。也就是說(shuō)在一段連續(xù)的物理內(nèi)存上,可能0~4(這個(gè)值取決于頁(yè)面的大小)屬于A,而5~9屬于B,10~14屬于C,從而保證任何一個(gè)“內(nèi)存片段”都可以被分配出去。
二百一十五、高級(jí)語(yǔ)言為什么不直接編譯成機(jī)器碼,而編譯成匯編代碼
1.一般的編譯器,是先將高級(jí)語(yǔ)言轉(zhuǎn)換成匯編語(yǔ)言(中間代碼),然后在匯編的基礎(chǔ)上優(yōu)化生成OBJ目標(biāo)代碼,最后Link成可執(zhí)行文件。
2.Que:高級(jí)語(yǔ)言為什么不直接編譯成機(jī)器碼,而編譯成匯編代碼?
ACK:1)其中有一個(gè)好處是方便優(yōu)化,因?yàn)?#xff0c;編譯器也是工具,也是機(jī)器,畢竟是機(jī)器生成的程序,不可以非常 完美的,而匯編是機(jī)器指令的助記符,一個(gè)匯編指令就對(duì)應(yīng)一條機(jī)器指令(特殊指令除外)調(diào)試起來(lái)肯定會(huì)比 機(jī)器指令方便的方便,這樣優(yōu)化起來(lái)也方便。
2)高級(jí)語(yǔ)言只需要編譯成匯編代碼就可以了,匯編代碼到機(jī)器碼的轉(zhuǎn)換是由硬件實(shí)現(xiàn)即可,有必要用軟件實(shí) 現(xiàn)這樣分層可以有效地減弱編譯器編寫(xiě)的復(fù)雜性,提高了效率.就像網(wǎng)絡(luò)通訊的實(shí)現(xiàn)需要分成很多層一樣,主要 目的就是為了從人腦可分析的粒度來(lái)減弱復(fù)雜性.
3)如果把高級(jí)語(yǔ)言的源代碼直接編譯成機(jī)器碼的話,那要做高級(jí)語(yǔ)言到機(jī)器碼之間的映射,如果這樣做的 話,每個(gè)寫(xiě)編譯器的都必須熟練機(jī)器碼。這個(gè)不是在做重復(fù)勞動(dòng)么。
二百一十六、全雙工 VS 半雙工
全雙工(Full Duplex)是指在發(fā)送數(shù)據(jù)的同時(shí)也能夠接收數(shù)據(jù),兩者同步進(jìn)行,這好像我們平時(shí)打電話一樣,說(shuō)話的同時(shí)也能夠聽(tīng)到對(duì)方的聲音。目前的網(wǎng)卡一般都支持全雙工。
半雙工(Half Duplex),所謂半雙工就是指一個(gè)時(shí)間段內(nèi)只有一個(gè)動(dòng)作發(fā)生,舉個(gè)簡(jiǎn)單例子,一條窄窄的馬路,同時(shí)只能有一輛車通過(guò),當(dāng)目前有兩量車對(duì)開(kāi),這種情況下就只能一輛先過(guò),等到頭兒后另一輛再開(kāi),這個(gè)例子就形象的說(shuō)明了半雙工的原理。早期的對(duì)講機(jī)、以及早期集線器等設(shè)備都是基于半雙工的產(chǎn)品。隨著技術(shù)的不斷進(jìn)步,半雙工會(huì)逐漸退出歷史舞臺(tái).
單工通信是指通信線路上的數(shù)據(jù)按單一方向傳送
TCP/UDP都是全雙工的
二百一十七、MSS
在有些書(shū)中,將它看作可“協(xié)商”選項(xiàng)。它并不是任何條件下都可協(xié)商。當(dāng)建立一個(gè)連
接時(shí),每一方都有用于通告它期望接收的MSS選項(xiàng)(MSS選項(xiàng)只能出現(xiàn)在SYN報(bào)文段中)。如果一方不接收來(lái)自另一方的MSS值,則MSS就定為默認(rèn)值536字節(jié)(這個(gè)默認(rèn)值允許20字節(jié)的IP首部和20字節(jié)的TCP首部以適合576字節(jié)IP數(shù)據(jù)報(bào))。
一般說(shuō)來(lái),如果沒(méi)有分段發(fā)生,MSS還是越大越好(這也并不總是正確,參見(jiàn)圖24-3和
圖24-4中的例子)。報(bào)文段越大允許每個(gè)報(bào)文段傳送的數(shù)據(jù)就越多,相對(duì)IP和TCP首部有更高的網(wǎng)絡(luò)利用率。當(dāng)TCP發(fā)送一個(gè)SYN時(shí),或者是因?yàn)橐粋€(gè)本地應(yīng)用進(jìn)程想發(fā)起一個(gè)連接,或
者是因?yàn)榱硪欢说闹鳈C(jī)收到了一個(gè)連接請(qǐng)求,它能將MSS值設(shè)置為外出接口上的MTU長(zhǎng)度減
去固定的IP首部和TCP首部長(zhǎng)度。對(duì)于一個(gè)以太網(wǎng),MSS值可達(dá)1460字節(jié)。使用IEEE802.3的
封裝(參見(jiàn)2.2節(jié)),它的MSS可達(dá)1452字節(jié)。
二百一十八、Linux配色修改
http://blog.csdn.net/hexinzheng19780209/article/details/45539431
https://www.zhihu.com/question/20110072
二百一十九、網(wǎng)絡(luò)傳輸包大小是否固定問(wèn)題
IP、TCP、UDP報(bào)頭詳見(jiàn):http://blog.csdn.net/Scythe666/article/details/51909186
TCP/IP協(xié)議定義了一個(gè)在因特網(wǎng)上傳輸?shù)陌?#xff0c;稱為IP數(shù)據(jù)包,而IP數(shù)據(jù)報(bào)(IP Datagram)是個(gè)比較抽象的內(nèi)容,是對(duì)數(shù)據(jù)包的結(jié)構(gòu)進(jìn)行分析。 由首部和數(shù)據(jù)兩部分組成,其格式如圖所示。首部的前一部分是固定長(zhǎng)度,共20字節(jié),是所有IP數(shù)據(jù)報(bào)必須具有的。在首部的固定部分的后面是一些可選字段,其長(zhǎng)度是可變的。首部中的源地址和目的地址都是IP協(xié)議地址。
總長(zhǎng)度指首部和數(shù)據(jù)之和的長(zhǎng)度,單位為字節(jié)。總長(zhǎng)度字段為16位,因此數(shù)據(jù)報(bào)的最大長(zhǎng)度為2^16-1=65535字節(jié)。
在IP層下面的每一種數(shù)據(jù)鏈路層都有自己的幀格式,其中包括幀格式中的數(shù)據(jù)字段的最大長(zhǎng)度,這稱為最大傳送單元MTU(Maximum Transfer Unit)。當(dāng)一個(gè)數(shù)據(jù)報(bào)封裝成鏈路層的幀時(shí),此數(shù)據(jù)報(bào)的總長(zhǎng)度(即首部加上數(shù)據(jù)部分)不能超過(guò)下面的數(shù)據(jù)鏈路層的MTU值。
深入淺出好文:http://www.cnblogs.com/maowang1991/archive/2013/04/15/3022955.html
二百二十、以太網(wǎng) VS 令牌環(huán)網(wǎng)
以太網(wǎng)是這樣通信的,每臺(tái)電腦位于同一個(gè)主干中都可以向主干線路中發(fā)信息串。假如a吧,它先監(jiān)聽(tīng)主干線路上有沒(méi)有人在發(fā)信息,如果有它就等一會(huì)兒,在它發(fā)現(xiàn)沒(méi)有人發(fā)言后它將發(fā)言,但這時(shí)有可能另一臺(tái)電腦也和它同時(shí)發(fā)言(想象一下在課堂上兩個(gè)學(xué)生向老師同時(shí)提問(wèn)),這樣它們會(huì)同時(shí)停止發(fā)言,并在等待了一個(gè)隨機(jī)時(shí)間后繼續(xù)發(fā)言,當(dāng)然它們的隨機(jī)時(shí)間是不同的,并且在再次發(fā)言前仍需監(jiān)聽(tīng)主干上是否有其它主機(jī)在發(fā)言。其它的電腦讀取數(shù)據(jù)包,檢查mac地址和ip地址乃至端口號(hào)看是不是發(fā)給自已的,如果不是便丟棄。它的mac 算法是csma/cd算法
令牌環(huán)網(wǎng)的結(jié)構(gòu)是組成一個(gè)環(huán)形,環(huán)形的一圈是主機(jī),主機(jī)中存在一個(gè)令牌,由一號(hào)機(jī)向下傳,每個(gè)主機(jī)只有在自已有令牌時(shí)才能向主線路中發(fā)數(shù)據(jù)。
二百二十一、MSS與MTU的關(guān)系(TCP分段和IP分割和重組報(bào)文)
MSS 指的是 TCP payload 的長(zhǎng)度,MSS讓主機(jī)限制另一端發(fā)送數(shù)據(jù)報(bào)的長(zhǎng)度。加上主機(jī)也能控制它發(fā)送數(shù)據(jù)報(bào)的長(zhǎng)度,這將使以較小 MTU連接到一個(gè)網(wǎng)絡(luò)上的主機(jī)避免分段。
為什么 L3 有 MTU 后 L4 還要 MSS 呢?
MTU 和 MSS 的功能其實(shí)基本一致, 都可以根據(jù)對(duì)應(yīng)的包大小進(jìn)行分片, 但實(shí)現(xiàn)的效果卻不太一樣.
L3 (IP) 提供的是一個(gè)不可靠的傳輸方式, 如果任何一個(gè)包在傳輸?shù)倪^(guò)程中丟失了, L3 是無(wú)法發(fā)現(xiàn)的, 需要靠上層應(yīng)用來(lái)保證. 就是說(shuō)如果一個(gè)大 IP 包分片后傳輸, 丟了任何一個(gè)部分都無(wú)法組合出完整的 IP 包, 即是上層應(yīng)用發(fā)現(xiàn)了傳輸失敗, 也無(wú)法做到僅重傳丟失的分片, 只能把 IP 包整個(gè)重傳. 那 IP 包越大的話重傳的代價(jià)也就越高.
L4 (TCP) 提供的是一個(gè)可靠的傳輸方式, 與 L3 不同的是, TCP 自身實(shí)現(xiàn)了重傳機(jī)制, 丟了任何一片數(shù)據(jù)報(bào)都能單獨(dú)重傳, 所以 TCP 為了高效傳輸, 是需要極力避免被 L3 分片的, 所以就有了 MSS 標(biāo)志, 并且 MSS 的值就是根據(jù) MTU 計(jì)算得出, 既避免了 L3 上的分片, 又保證的最大的傳輸效率.
http://networkengineering.stackexchange.com/questions/8288/difference-between-mss-and-mtu
http://blog.apnic.net/2014/12/15/ip-mtu-and-tcp-mss-missmatch-an-evil-for-network-performance/
二百二十二、都說(shuō)路由器可以設(shè)置MTU,為什么是第三層設(shè)備設(shè)置呢
最大傳輸單元,即物理接口(數(shù)據(jù)鏈路層)提供給其上層(通常是IP層)最大一次傳輸數(shù)據(jù)的大小
二百二十三、不是說(shuō)TCP報(bào)頭沒(méi)有長(zhǎng)度限制嗎,MSS又是什么
詳見(jiàn)兩篇超好的知乎文章,車小胖:https://zhuanlan.zhihu.com/p/21268782
https://www.zhihu.com/question/48454744
二百二十四、TCP/IP 協(xié)議棧為什么有粘包問(wèn)題,如何解決
如何解決
(1)加入分隔符字段,自己定義結(jié)束標(biāo)志
(2)加入payload長(zhǎng)度字段(注意是加入一個(gè)字段),比如http應(yīng)用層協(xié)議就是這樣做的
二百二十五、網(wǎng)絡(luò)傳輸?shù)臅r(shí)候有大小端的問(wèn)題,如何解決
二百二十六、為什么TCP要三次握手
二百二十七、TCP四次揮手,為什么要等待2MSL
什么是MSL
二百二十八、TCP有限狀態(tài)機(jī)
三次握手、四次揮手中發(fā)起端(左邊)是粗實(shí)線狀態(tài)
右邊是粗虛線狀態(tài)
二百二十九、裝飾器模式與代理的區(qū)別
實(shí)現(xiàn)手段差不多,但是目的有微妙的差別
裝飾器模式:基于原有功能的加強(qiáng),主要是功能的差別,而且功能只能加強(qiáng),例子Java IO流
代理:由另一個(gè)類去執(zhí)行,主要是執(zhí)行者的差別,當(dāng)然功能可以加強(qiáng)可以減弱
二百三十、Linux系統(tǒng)uid
用戶的UID大于500的都是非系統(tǒng)賬號(hào),500以下的都為系統(tǒng)保留的賬號(hào),比如root賬號(hào),至高權(quán)限的賬號(hào)的UID為0,我們創(chuàng)建用戶的時(shí)候默認(rèn)的賬號(hào)的UID都是大于500,如果你要指定賬號(hào)的UID可以使用-u這個(gè)參數(shù)來(lái)指定。其它沒(méi)什么大的意義。
二百三十一、什么是驅(qū)動(dòng)
驅(qū)動(dòng)程序雖然在你打開(kāi)電腦進(jìn)入系統(tǒng)之后就不斷地在為你服務(wù)了,但是它不像電腦硬件那樣觸手可及,也不像操作系統(tǒng)那樣一目了然,更不像游戲或者多媒體應(yīng)用那樣引人注目,它只是默默無(wú)聞的在后臺(tái)做著自己該做的事情,因此總是被很多朋友忽略。
那么驅(qū)動(dòng)是什么呢?驅(qū)動(dòng)的英文就是Driver,簡(jiǎn)單的說(shuō)來(lái)驅(qū)動(dòng)程序就是用來(lái)向操作系統(tǒng)提供一個(gè)訪問(wèn)、使用硬件設(shè)備的接口,實(shí)現(xiàn)操作系統(tǒng)和系統(tǒng)中所有的硬件設(shè)備的之間的通信程序,它能告訴系統(tǒng)硬件設(shè)備所包含的功能,并且在軟件系統(tǒng)要實(shí)現(xiàn)某個(gè)功能時(shí),調(diào)動(dòng)硬件并使硬件用最有效的方式來(lái)完成它。
說(shuō)的形象一點(diǎn),驅(qū)動(dòng)程序就是軟件與硬件之間的“傳令兵”,這個(gè)環(huán)節(jié)可是大大的重要,一旦出現(xiàn)了問(wèn)題,那么軟件提出的要求就要無(wú)人響應(yīng),而硬件卻空有一身力氣但無(wú)從發(fā)揮,那種狀況下朋友們會(huì)發(fā)現(xiàn)自己那本來(lái)性能強(qiáng)大且多姿多彩的電腦竟然如同一洼死水,什么都做不來(lái)了。因此有人說(shuō)驅(qū)動(dòng)是硬件的靈魂,可毫不為過(guò)。
二百三十二、CPU使用分時(shí)間片,會(huì)不會(huì)很浪費(fèi)資源
時(shí)間片輪轉(zhuǎn)調(diào)度中特別需要關(guān)注的是時(shí)間片的長(zhǎng)度。從一個(gè)進(jìn)程切換到另一個(gè)進(jìn)程是需要一定時(shí)間的–保存和裝入寄存器值及內(nèi)存映像,更新各種表格和隊(duì)列等。假如進(jìn)程切換(process switch) - 有時(shí)稱為上下文切換(context switch),需要5毫秒,再假設(shè)時(shí)間片設(shè)為20毫秒,則在做完20毫秒有用的工作之后,CPU將花費(fèi)5毫秒來(lái)進(jìn)行進(jìn)程切換。CPU時(shí)間的20%被浪費(fèi)在了管理開(kāi)銷上。
為了提高CPU效率,我們可以將時(shí)間片設(shè)為500毫秒。這時(shí)浪費(fèi)的時(shí)間只有1%。但考慮在一個(gè)分時(shí)系統(tǒng)中,如果有十個(gè)交互用戶幾乎同時(shí)按下回車鍵,將發(fā)生什么情況?假設(shè)所有其他進(jìn)程都用足它們的時(shí)間片的話,最后一個(gè)不幸的進(jìn)程不得不等待5秒鐘才獲得運(yùn)行機(jī)會(huì)。多數(shù)用戶無(wú)法忍受一條簡(jiǎn)短命令要5秒鐘才能做出響應(yīng)。同樣的問(wèn)題在一臺(tái)支持多道程序的個(gè)人計(jì)算機(jī)上也會(huì)發(fā)生。
結(jié)論可以歸結(jié)如下:時(shí)間片設(shè)得太短會(huì)導(dǎo)致過(guò)多的進(jìn)程切換,降低了CPU效率;而設(shè)得太長(zhǎng)又可能引起對(duì)短的交互請(qǐng)求的響應(yīng)變差。
二百三十三、主分區(qū)、擴(kuò)展分區(qū)、邏輯分區(qū)
一個(gè)硬盤(pán)的主分區(qū)也就是包含操作系統(tǒng)啟動(dòng)所必需的文件和數(shù)據(jù)的硬盤(pán)分區(qū),要在硬盤(pán)上安裝操作系統(tǒng),則該硬盤(pán)必須得有一個(gè)主分區(qū)。
擴(kuò)展分區(qū)也就是除主分區(qū)外的分區(qū),但它不能直接使用,必須再將它劃分為若干個(gè)邏輯分區(qū)才行。邏輯分區(qū)也就是我們平常在操作系統(tǒng)中所看到的D、E、F等盤(pán)。
不管使用哪種分區(qū)軟件,我們?cè)诮o新硬盤(pán)上建立分區(qū)時(shí)都要遵循以下的順序:建立主分區(qū)→建立擴(kuò)展分區(qū)→建立邏輯分區(qū)→激活主分區(qū)→格式化所有分區(qū)。
總結(jié)
以上是生活随笔為你收集整理的[置顶] C/C++超级大火锅的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 组件的 props
- 下一篇: VC++得到系统特殊文件夹路径