姓名:王重月? 學(xué)號(hào):21021211019? ?學(xué)院:電子工程學(xué)院
轉(zhuǎn)自:(30條消息) 嵌入式必備知識(shí)_Oliver.H的博客-CSDN博客_嵌入式基本知識(shí)必備
【嵌牛導(dǎo)讀】介紹C和C++的區(qū)別,概念等
【嵌牛鼻子】C和C++
【嵌牛提問(wèn)】C和C++的區(qū)別到底有哪里不一樣柒凉?
【嵌牛正文】
2.1 c和c++區(qū)別喂柒、概念相關(guān)面試題
屬性:
new/delete是C++關(guān)鍵字,需要編譯器支持。malloc/free是庫(kù)函數(shù)奶浦,需要頭文件支持私痹。
特征:
2.1.2 malloc的底層實(shí)現(xiàn)
Linux維護(hù)一個(gè)break指針,這個(gè)指針指向堆空間的某個(gè)地址匠抗。從堆起始地址到break之間的地址空間為映射好的故源,可以供進(jìn)程訪問(wèn);而從break往上汞贸,是未映射的地址空間绳军,如果訪問(wèn)這段空間則程序會(huì)報(bào)錯(cuò)印机。我們用malloc進(jìn)行內(nèi)存分配就是從break往上進(jìn)行的。 獲得了break指針的位置也就得到了堆內(nèi)存申請(qǐng)的起始地址门驾。
malloc實(shí)際上是將可用空間用一個(gè)空閑鏈表連接起來(lái)射赛,若用戶申請(qǐng)空間,就遍歷該鏈表奶是,找到第一個(gè)滿足條件的空閑塊楣责,將其進(jìn)行拆分,返回合適大小的空間給用戶聂沙,將剩下的部分鏈接到鏈表中秆麸。當(dāng)調(diào)用free釋放空間時(shí),會(huì)把這塊空間連接到空閑鏈表上逐纬。到最后蛔屹,該空閑鏈就會(huì)被切成很多的小內(nèi)存塊,一旦用戶申請(qǐng)一塊較大的空間豁生,空閑鏈中的空間大小都無(wú)法滿足需求兔毒,malloc會(huì)申請(qǐng)延時(shí),對(duì)空閑鏈表進(jìn)行檢查甸箱,內(nèi)存重新整理育叁,把相鄰的小片段合并成大的空閑塊。
2.1.3 在1G內(nèi)存的計(jì)算機(jī)中能否malloc(1.2G)芍殖?為什么豪嗽?
malloc能夠申請(qǐng)的空間大小與物理內(nèi)存的大小沒(méi)有直接關(guān)系,僅與程序的虛擬地址空間相關(guān)豌骏。程序運(yùn)行時(shí)龟梦,堆空間只是程序向操作系統(tǒng)申請(qǐng)劃出來(lái)的一大塊虛擬地址空間。應(yīng)用程序通過(guò)malloc申請(qǐng)空間窃躲,得到的是在虛擬地址空間中的地址计贰,之后程序運(yùn)行所提供的物理內(nèi)存是由操作系統(tǒng)完成的。
2.1.4 指針與引用的相同和區(qū)別蒂窒;如何相互轉(zhuǎn)換躁倒?
共性:
1)都是地址的概念,指針指向某一內(nèi)存洒琢、它的內(nèi)容是所指內(nèi)存的地址秧秉;引用則是某塊內(nèi)存的別名。
2)從內(nèi)存分配上看:兩者都占內(nèi)存衰抑,程序?yàn)橹羔槙?huì)分配內(nèi)存象迎,一般是4個(gè)字節(jié);而引用的本質(zhì)是指針常量呛踊,指向?qū)ο蟛荒茏兝剩赶驅(qū)ο蟮闹悼梢宰兺昀觥烧叨际堑刂犯拍睿员旧矶紩?huì)占用內(nèi)存拇舀。
區(qū)別:
1)引用必須被初始化,指針不必蜻底。
2)引用初始化以后不能被改變骄崩,指針可以改變所指的對(duì)象。
3)不存在指向空值的引用薄辅,但是存在指向空值的指針要拂。
轉(zhuǎn)換:
指針轉(zhuǎn)引用:把指針用*就可以轉(zhuǎn)換成對(duì)象,可以用在引用參數(shù)當(dāng)中站楚。
引用轉(zhuǎn)指針:把引用類型的對(duì)象用&取地址就獲得指針了脱惰。
2.1.5 C語(yǔ)言檢索內(nèi)存情況 內(nèi)存分配的方式
一個(gè)程序本質(zhì)上都是由BSS段、data段窿春、text段三個(gè)組成的拉一。可以看到一個(gè)可執(zhí)行程序在存儲(chǔ)(沒(méi)有調(diào)入內(nèi)存)時(shí)分為代碼段旧乞、數(shù)據(jù)區(qū)和未初始化數(shù)據(jù)區(qū)三部分蔚润。
BSS段(未初始化數(shù)據(jù)區(qū)):通常用來(lái)存放程序中未初始化的全局變量和靜態(tài)變量的一塊內(nèi)存區(qū)域。BSS段屬于靜態(tài)分配尺栖,程序結(jié)束后靜態(tài)變量資源由系統(tǒng)自動(dòng)釋放嫡纠。
數(shù)據(jù)段:存放程序中已初始化的全局變量的一塊內(nèi)存區(qū)域。數(shù)據(jù)段也屬于靜態(tài)內(nèi)存分配
代碼段:存放程序執(zhí)行代碼的一塊內(nèi)存區(qū)域延赌。這部分區(qū)域的大小在程序運(yùn)行前就已經(jīng)確定除盏,并且內(nèi)存區(qū)域?qū)儆谥蛔x。在代碼段中挫以,也有可能包含一些只讀的常數(shù)變量
text段和data段在編譯時(shí)已經(jīng)分配了空間者蠕,而BSS段并不占用可執(zhí)行文件的大小,它是由鏈接器來(lái)獲取內(nèi)存的屡贺。
bss段(未進(jìn)行初始化的數(shù)據(jù))的內(nèi)容并不存放在磁盤上的程序文件中蠢棱。其原因是內(nèi)核在程序開始運(yùn)行前將它們?cè)O(shè)置為0。需要存放在程序文件中的只有正文段和初始化數(shù)據(jù)段甩栈。
data段(已經(jīng)初始化的數(shù)據(jù))則為數(shù)據(jù)分配空間泻仙,數(shù)據(jù)保存到目標(biāo)文件中。
數(shù)據(jù)段包含經(jīng)過(guò)初始化的全局變量以及它們的值量没。BSS段的大小從可執(zhí)行文件中得到玉转,然后鏈接器得到這個(gè)大小的內(nèi)存塊,緊跟在數(shù)據(jù)段的后面殴蹄。當(dāng)這個(gè)內(nèi)存進(jìn)入程序的地址空間后全部清零究抓。包含數(shù)據(jù)段和BSS段的整個(gè)區(qū)段此時(shí)通常稱為數(shù)據(jù)區(qū)猾担。
可執(zhí)行程序在運(yùn)行時(shí)又多出兩個(gè)區(qū)域:棧區(qū)和堆區(qū)。
**棧區(qū):**由編譯器自動(dòng)釋放刺下,存放函數(shù)的參數(shù)值绑嘹、局部變量等。每當(dāng)一個(gè)函數(shù)被調(diào)用時(shí)橘茉,該函數(shù)的返回類型和一些調(diào)用的信息被存放到棧中工腋。然后這個(gè)被調(diào)用的函數(shù)再為他的自動(dòng)變量和臨時(shí)變量在棧上分配空間。每調(diào)用一個(gè)函數(shù)一個(gè)新的棧就會(huì)被使用畅卓。棧區(qū)是從高地址位向低地址位增長(zhǎng)的擅腰,是一塊連續(xù)的內(nèi)存區(qū)域,最大容量是由系統(tǒng)預(yù)先定義好的翁潘,申請(qǐng)的棾酶裕空間超過(guò)這個(gè)界限時(shí)會(huì)提示溢出,用戶能從棧中獲取的空間較小拜马。
**堆區(qū):**用于動(dòng)態(tài)分配內(nèi)存渗勘,位于BSS和棧中間的地址區(qū)域。由程序員申請(qǐng)分配和釋放一膨。堆是從低地址位向高地址位增長(zhǎng)呀邢,采用鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)。頻繁的malloc/free造成內(nèi)存空間的不連續(xù)豹绪,產(chǎn)生碎片价淌。當(dāng)申請(qǐng)堆空間時(shí)庫(kù)函數(shù)是按照一定的算法搜索可用的足夠大的空間。因此堆的效率比棧要低的多瞒津。
2.1.6 extern”C” 的作用
extern "C"的主要作用就是為了能夠正確實(shí)現(xiàn)C++代碼調(diào)用其他C語(yǔ)言代碼蝉衣。加上extern "C"后,會(huì)指示編譯器這部分代碼按C語(yǔ)言的進(jìn)行編譯巷蚪,而不是C++的病毡。由于C++支持函數(shù)重載,因此編譯器編譯函數(shù)的過(guò)程中會(huì)將函數(shù)的參數(shù)類型也加到編譯后的代碼中屁柏,而不僅僅是函數(shù)名啦膜;而C語(yǔ)言并不支持函數(shù)重載,因此編譯C語(yǔ)言代碼的函數(shù)時(shí)不會(huì)帶上函數(shù)的參數(shù)類型淌喻,一般只包括函數(shù)名僧家。
2.1.7頭文件聲明時(shí)加extern定義時(shí)不要加 因?yàn)閑xtern可以多次聲明,但只有一個(gè)定義
2.1.8函數(shù)參數(shù)壓棧順序裸删,即關(guān)于stdcall和cdecl調(diào)用方式的理解
stdcall和cdecl都是函數(shù)調(diào)用約定關(guān)鍵字:
stdcall:參數(shù)由右向左壓入堆棧八拱;堆棧由函數(shù)本身清理。
cdecl:參數(shù)也是由右向左壓入堆棧;但堆棧由調(diào)用者清理肌稻。
2.1.9重寫memcpy()函數(shù)需要注意哪些問(wèn)題
2.1.10數(shù)組到底存放在哪里
2.1.11 struct和class的區(qū)別
相同點(diǎn):
struct能包含成員函數(shù)嗎清蚀? 能!
struct能繼承嗎爹谭? 能<闲啊!
struct能實(shí)現(xiàn)多態(tài)嗎诺凡? 能3莘纭!绑洛!
不同點(diǎn):
(1)關(guān)于使用大括號(hào)初始化
class和struct如果定義了構(gòu)造函數(shù),就不能用大括號(hào)進(jìn)行初始化了童本;若沒(méi)有定義真屯,struct可以用大括號(hào)初始化,而class只有在所有成員變量全是public的情況下穷娱,才可以用大括號(hào)進(jìn)行初始化
(2)關(guān)于默認(rèn)權(quán)限訪問(wèn)
class中默認(rèn)成員訪問(wèn)權(quán)限是private,而struct的默認(rèn)訪問(wèn)權(quán)限是public
(3)關(guān)于繼承方式
class中默認(rèn)繼承方式是private,而struct的默認(rèn)繼承方式是public绑蔫,具體代碼如下
2.1.12 char和int之間的轉(zhuǎn)換
將字符char類型轉(zhuǎn)換成int整型
將字符串轉(zhuǎn)化成int
將int整型轉(zhuǎn)化成字符串型
2.1.13 static的用法(定義和用途)
全局靜態(tài)變量
在全局變量前加上關(guān)鍵字static,全局變量就定義成一個(gè)全局靜態(tài)變量.
靜態(tài)存儲(chǔ)區(qū)泵额,在整個(gè)程序運(yùn)行期間一直存在配深。
初始化:未經(jīng)初始化的全局靜態(tài)變量會(huì)被自動(dòng)初始化為0(自動(dòng)對(duì)象的值是任意的,除非他被顯式初始化)嫁盲;
作用域:全局靜態(tài)變量在聲明他的文件之外是不可見的篓叶,準(zhǔn)確地說(shuō)是從定義之處開始,到文件結(jié)尾羞秤。
局部靜態(tài)變量
在局部變量之前加上關(guān)鍵字static缸托,局部變量就成為一個(gè)局部靜態(tài)變量。
內(nèi)存中的位置:靜態(tài)存儲(chǔ)區(qū)
初始化:未經(jīng)初始化的全局靜態(tài)變量會(huì)被自動(dòng)初始化為0(自動(dòng)對(duì)象的值是任意的瘾蛋,除非他被顯式初始化)俐镐;
作用域:作用域仍為局部作用域,當(dāng)定義它的函數(shù)或者語(yǔ)句塊結(jié)束的時(shí)候哺哼,作用域結(jié)束佩抹。但是當(dāng)局部靜態(tài)變量離開作用域后,并沒(méi)有銷毀取董,而是仍然駐留在內(nèi)存當(dāng)中棍苹,只不過(guò)我們不能再對(duì)它進(jìn)行訪問(wèn),直到該函數(shù)再次被調(diào)用甲葬,并且值不變廊勃;
靜態(tài)函數(shù)
在函數(shù)返回類型前加static,函數(shù)就定義為靜態(tài)函數(shù)。函數(shù)的定義和聲明在默認(rèn)情況下都是extern的坡垫,但靜態(tài)函數(shù)只是在聲明他的文件當(dāng)中可見梭灿,不能被其他文件所用。
函數(shù)的實(shí)現(xiàn)使用static修飾冰悠,那么這個(gè)函數(shù)只可在本cpp內(nèi)使用堡妒,不會(huì)同其他cpp中的同名函數(shù)引起沖突;
warning:不要再頭文件中聲明static的全局函數(shù)溉卓,不要在cpp內(nèi)聲明非static的全局函數(shù)皮迟,如果你要在多個(gè)cpp中復(fù)用該函數(shù),就把它的聲明提到頭文件里去桑寨,否則cpp內(nèi)部聲明需加上static修飾伏尼;
類的靜態(tài)成員
在類中,靜態(tài)成員可以實(shí)現(xiàn)多個(gè)對(duì)象之間的數(shù)據(jù)共享尉尾,并且使用靜態(tài)數(shù)據(jù)成員還不會(huì)破壞隱藏的原則爆阶,即保證了安全性。因此沙咏,靜態(tài)成員是類的所有對(duì)象中共享的成員辨图,而不是某個(gè)對(duì)象的成員。對(duì)多個(gè)對(duì)象來(lái)說(shuō)肢藐,靜態(tài)數(shù)據(jù)成員只存儲(chǔ)一處故河,供所有對(duì)象共用
類的靜態(tài)函數(shù)
靜態(tài)成員函數(shù)和靜態(tài)數(shù)據(jù)成員一樣,它們都屬于類的靜態(tài)成員吆豹,它們都不是對(duì)象成員鱼的。因此,對(duì)靜態(tài)成員的引用不需要用對(duì)象名痘煤。
在靜態(tài)成員函數(shù)的實(shí)現(xiàn)中不能直接引用類中說(shuō)明的非靜態(tài)成員鸳吸,可以引用類中說(shuō)明的靜態(tài)成員(這點(diǎn)非常重要)。如果靜態(tài)成員函數(shù)中要引用非靜態(tài)成員時(shí)速勇,可通過(guò)對(duì)象來(lái)引用晌砾。從中可看出,調(diào)用靜態(tài)成員函數(shù)使用如下格式:<類名>::<靜態(tài)成員函數(shù)名>(<參數(shù)表>);
2.1.15const常量和#define的區(qū)別(編譯階段烦磁、安全性养匈、內(nèi)存占用等)
編譯器處理不同
宏定義是一個(gè)“編譯時(shí)”概念,在預(yù)處理階段展開(在編譯時(shí)把所有用到宏定義值的地方用宏定義常量替換)都伪,不能對(duì)宏定義進(jìn)行調(diào)試呕乎,生命周期結(jié)束于編譯時(shí)期;
const常量是一個(gè)“運(yùn)行時(shí)”概念陨晶,在程序運(yùn)行使用猬仁,類似于一個(gè)只讀行數(shù)據(jù)
存儲(chǔ)方式不同
宏定義是直接替換帝璧,不會(huì)分配內(nèi)存,存儲(chǔ)與程序的代碼段中湿刽;
const常量需要進(jìn)行內(nèi)存分配
類型和安全檢查不同
宏定義是字符替換的烁,沒(méi)有數(shù)據(jù)類型的區(qū)別,同時(shí)這種替換沒(méi)有類型安全檢查诈闺,可能產(chǎn)生邊際效應(yīng)等錯(cuò)誤渴庆;
const常量是常量的聲明,有類型區(qū)別雅镊,需要在編譯階段進(jìn)行類型檢查
2.1.16 volatile作用和用法
作用:
Volatile意思是“易變的”襟雷,應(yīng)該解釋為“直接存取原始內(nèi)存地址”比較合適。 “易變”是因?yàn)橥庠谝蛩匾鸬娜逝耄穸嗑€程耸弄,中斷等;
C語(yǔ)言書籍這樣定義volatile關(guān)鍵字:volatile提醒編譯器它后面所定義的變量隨時(shí)都有可能改變卓缰,因此編譯后的程序每次需要存儲(chǔ)或讀取這個(gè)變量的時(shí)候叙赚,告訴編譯器對(duì)該變量不做優(yōu)化,都會(huì)直接從變量?jī)?nèi)存地址中讀取數(shù)據(jù)僚饭,從而可以提供對(duì)特殊地址的穩(wěn)定訪問(wèn)。胧砰。如果沒(méi)有volatile關(guān)鍵字鳍鸵,則編譯器可能優(yōu)化讀取和存儲(chǔ),可能暫時(shí)使用寄存器中的值尉间,如果這個(gè)變量由別的程序更新了的話偿乖,將出現(xiàn)不一致的現(xiàn)象。(簡(jiǎn)潔的說(shuō)就是:volatile關(guān)鍵詞影響編譯器編譯的結(jié)果哲嘲,用volatile聲明的變量表示該變量隨時(shí)可能發(fā)生變化贪薪,與該變量有關(guān)的運(yùn)算,不要進(jìn)行編譯優(yōu)化眠副,以免出錯(cuò))
下面是volatile變量的幾個(gè)例子:
1). 并行設(shè)備的硬件寄存器(如:狀態(tài)寄存器)
2). 一個(gè)中斷服務(wù)子程序中會(huì)訪問(wèn)到的非自動(dòng)變量(Non-automatic variables)
3). 多線程應(yīng)用中被幾個(gè)任務(wù)共享的變量
回答不出這個(gè)問(wèn)題的人是不會(huì)被雇傭的画切。我認(rèn)為這是區(qū)分C程序員和嵌入式系統(tǒng)程序員的最基本的問(wèn)題。嵌入式系統(tǒng)程序員經(jīng)常同硬件囱怕、中斷霍弹、RTOS等等打交道,所用這些都要求volatile變量娃弓。不懂得volatile內(nèi)容將會(huì)帶來(lái)災(zāi)難典格。
幾個(gè)問(wèn)題:
1)一個(gè)參數(shù)既可以是const還可以是volatile嗎?
可以的台丛,例如只讀的狀態(tài)寄存器耍缴。它是volatile因?yàn)樗赡鼙灰庀氩坏降馗淖儭K莄onst因?yàn)槌绦虿粦?yīng)該試圖去修改它。
2) 一個(gè)指針可以是volatile 嗎防嗡?
可以变汪,當(dāng)一個(gè)中服務(wù)子程序修改一個(gè)指向buffer的指針時(shí)。
3). 下面的函數(shù)有什么錯(cuò)誤:
這段代碼的目的是用來(lái)返指針ptr指向值的平方本鸣,但是疫衩,由于ptr指向一個(gè)volatile型參數(shù),編譯器將產(chǎn)生類似下面的代碼:
由于*ptr的值可能被意想不到地該變荣德,因此a和b可能是不同的闷煤。結(jié)果,這段代碼可能返不是你所期望的平方值涮瞻!正確的代碼如下:
注意:頻繁地使用volatile很可能會(huì)增加代碼尺寸和降低性能,因此要合理的使用volatile鲤拿。
2.1.17 有常量指針 指針常量 常量引用 沒(méi)有 引用常量
1.指針:指針代表一個(gè)變量的地址;
例如:
2.引用:引用即針對(duì)一個(gè)變量的別名署咽,引用必須被初始化近顷,引用作為參數(shù)(形參)時(shí),不會(huì)像指針一樣使用存儲(chǔ)單元宁否,更不會(huì)像值傳遞一樣創(chuàng)建該參數(shù)的副本窒升,提高空間/時(shí)間效率。
例如:int a=2,&b = a;
3.常量引用:格式為 const 變量類型 &變量名慕匠,當(dāng)聲明該引用時(shí)饱须,不可通過(guò)引用對(duì)其目標(biāo)變量的值進(jìn)行修改,變量自身可以修改台谊,可用于保證函數(shù)內(nèi)形參不可更改蓉媳,也就是保證傳入的實(shí)參為常量。
4.指向常量的指針:(《C++ Primer》書中名字是指向常量的指針锅铅,網(wǎng)上的叫法是“常量指針”)酪呻,const int *p;其本質(zhì)為一個(gè)指針,因?yàn)樵撝羔樦赶蛞粋€(gè)常量盐须,所以不能通過(guò)該指針修改常量的值玩荠,但該指針指向的也可為變量,重點(diǎn)在于不能通過(guò)該指針修改指向變量(常量)的值贼邓;
5.常量指針:(《C++ Primer》書中名字是常量指針姨蟋,網(wǎng)上的叫法是“指針常量”),int* const p;其本質(zhì)為一個(gè)常量,所以其指向的值可以改變立帖,但是由于指針為常量眼溶,所以聲明時(shí)必須初始化,且初始化后存放在指針中那個(gè)地址不可改變晓勇,此地址對(duì)應(yīng)的非常量值仍可被改變堂飞。
總結(jié): const在 * 的左邊灌旧,則為指向常量的指針,即指針指向的變量的值不可直接通過(guò)指針改變(可以通過(guò)其他途徑改變)绰筛;const在 * 的右邊枢泰,則為常量指針,即指針的指向不可變铝噩。簡(jiǎn)記為const的 “左定值衡蚂,右定向”。
2.1.19 c/c++中變量的作用域
對(duì)局部變量的兩點(diǎn)說(shuō)明:
1)main() 也是一個(gè)函數(shù)骏庸,在 main() 內(nèi)部定義的變量也是局部變量毛甲,只能在 main() 函數(shù)內(nèi)部使用。
2)形參也是局部變量具被,將實(shí)參傳遞給形參的過(guò)程玻募,就是用實(shí)參給局部變量賦值的過(guò)程,它和a=b; sum=m+n;這樣的賦值沒(méi)有什么區(qū)別一姿。
全局變量:
全局變量的默認(rèn)作用域是整個(gè)程序七咧,也就是所有的代碼文件,包括源文件(.c文件)和頭文件(.h文件)叮叹。如果給全局變量加上 static 關(guān)鍵字艾栋,它的作用域就變成了當(dāng)前文件,在其它文件中就無(wú)效了蛉顽。我們目前編寫的代碼都是在一個(gè)源文件中蝗砾,所以暫時(shí)不用考慮 static 關(guān)鍵字.
————————————————
版權(quán)聲明:本文為CSDN博主「Oliver.H」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權(quán)協(xié)議蜂林,轉(zhuǎn)載請(qǐng)附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/weixin_43253519/article/details/108351553