RM新时代网站-首页

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

C語言和C++中那些不同的地方

單片機與嵌入式 ? 來源:單片機與嵌入式 ? 2023-12-07 14:29 ? 次閱讀

C語言雖說經(jīng)常和C++在一起被大家提起,但可千萬不要以為它們是一個東西。現(xiàn)在我們常用的C語言是C89標準,C++是C++99標準的。C89就是在1989年制定的標準,如今最新的是C11和C++11標準。根據(jù)不同的標準,它們的功能也會有所不同,但是越新的版本支持的編譯器越少,所以本文在討論的時候使用的C語言標準是C89,C++標準是C++99.我們來介紹C語言和C++中那些不同的地方。

函數(shù)默認值

在C++中我們在定義或聲明一個函數(shù)的時候,有時會在形參中給它賦一個初始值作為不傳參數(shù)時候的缺省值,例如:

intFUN(inta=10);

代表沒有傳參調(diào)用的時候,自動給a賦一個10的初始值。然而這種操作在c89下是行不通的,在c語言下這么寫就會報錯。我們都知道,系統(tǒng)在調(diào)用任何一個函數(shù)的時候都有函數(shù)棧幀的開辟,如果函數(shù)有參數(shù)則需要壓入實參。平常在我們?nèi)藶榻o定實參的時候,是按照參數(shù)列表從右向左依次將參數(shù)通過指令傳入寄存器,再通過push指令壓入?,F(xiàn)在我們已經(jīng)給定了函數(shù)參數(shù)的默認值,那么在壓實參的時候只需要一步push初始值即可。效率更高。

另外需要注意的是,賦初始值必須從參數(shù)列表的右邊開始賦值,從左邊開始賦值將會出錯:

int sum1(int a = 10,int b);        //錯誤
int sum2(int a,int b = 20);            //正確

因為如果sum1的聲明是正確的,那么我們調(diào)用的時候怎么調(diào)用?

sum1( ,20)//?很可惜這樣屬于語法錯誤

調(diào)用這么寫既然不對那就當然不能這樣賦初始值了。

相反,來看下sum2的調(diào)用:

sum2(20);//合情合理,沒有任何問題

實際在寫工程的時候,我們都習慣將函數(shù)的聲明寫在頭文件中而非本文件

中,然后在不同的文件中寫出它們的定義。那么這種情況可以賦初始值嗎?

當然可以,不論是定義還是聲明處,只要你遵守從右向左賦的規(guī)則就可以。

甚至你還可以這樣給初始值:

int  fun(int a ,int b = 10);
int  fun(int a = 20,int b);

眼尖的同學看見了下面的那行代碼大喊錯誤,因為先給左邊賦值了!

其實這樣聲明完全沒有問題,兩句聲明是同一個函數(shù)(函數(shù)多次聲明沒有問題),第一句已經(jīng)給b了一個初始值,運行到第二句時已經(jīng)等價于

int fun(int a = 20,int b = 10);

但是注意,這兩句的順序不能反轉(zhuǎn),否則就是錯誤的。

總結(jié):C89標準的C語言不支持函數(shù)默認值,C++支持函數(shù)默認值,且需要遵循從右向左賦初始值。

inline內(nèi)聯(lián)函數(shù)

說到內(nèi)聯(lián)函數(shù)大家應(yīng)當不陌生,它又是一個C89標準下C語言沒有的函數(shù)。它的具體做法和宏非常相似,也是在調(diào)用處直接將代碼展開,只不過宏它是在預(yù)編譯階段展開,而內(nèi)聯(lián)函數(shù)是在 編譯階段進行處理的。同時,宏作為預(yù)處理并不進行類型檢查,而inline函數(shù)是要進行類型檢查的,也就可以稱作“更安全的宏”。

內(nèi)聯(lián)函數(shù)和普通函數(shù)的區(qū)別:內(nèi)聯(lián)函數(shù)沒有棧幀的開辟回退,一般我們直接把內(nèi)聯(lián)函數(shù)寫在頭文件中,include之后就可以使用,由于調(diào)用時直接代碼展開所以我們根本不需要擔心什么重定義的問題——它連符號都沒有生成當然不會所謂重定義了。普通函數(shù)生成符號,內(nèi)聯(lián)函數(shù)不會生成符號。

關(guān)于inline還需要注意的一點是,我們在使用它的時候往往是用來替換函數(shù)體非常?。?~5行代碼)的函數(shù)的。這種情況下函數(shù)的堆棧開銷相對函數(shù)體大小來說就非常大了,這種情況使用內(nèi)聯(lián)函數(shù)可以大大提高效率。相反如果是一個需要很多代碼才能實現(xiàn)的函數(shù),則不適合使用。一是此時函數(shù)堆棧調(diào)用開銷與函數(shù)體相比已經(jīng)是微不足道了,二是大量的代碼直接展開的話會給調(diào)試帶來很大的不便。三是如果代碼體達到一個閾值,編譯器會將它變成普通函數(shù)。

同時,遞歸函數(shù)不能聲明為inline函數(shù)。說到底inline只是對編譯器的建議,最終能否成功也不一定。同時,我們平常生成的都是debug版本,在這個版本下inline是不起作用的。只有生成release版時才會起作用。

總結(jié):C89沒有,在調(diào)用點直接展開,不生成符號,沒有棧幀的開辟回退,僅在Release版本下生效。一般寫在頭文件中。

函數(shù)重載

C語言中產(chǎn)生函數(shù)符號的規(guī)則是根據(jù)名稱產(chǎn)生,這也就注定了c語言不存在函數(shù)重載的概念。而C++生成函數(shù)符號則考慮了函數(shù)名、參數(shù)個數(shù)、參數(shù)類型。需要注意的是函數(shù)的返回值并不能作為函數(shù)重載的依據(jù),也就是說int sum和double sum這兩個函數(shù)是不能構(gòu)成重載的!

我們的函數(shù)重載也屬于多態(tài)的一種,這就是所謂的靜多態(tài)。

靜多態(tài):函數(shù)重載,函數(shù)模板

動多態(tài)(運行時的多態(tài)):繼承中的多態(tài)(虛函數(shù))

使用重載的時候需要注意作用域問題,請看如下代碼:

#include
usingnamespacestd;
bool compare(int a,int b)
{
return a > b;
}
bool  compare(double a,double b)
{
return a > b;
}
int main()
{
//bool compare(int a,int b);
compare(10,20);
compare(10.5,20.5);
return 0;
}

我在全局作用域定義了兩個函數(shù),它們由于參數(shù)類型不同可以構(gòu)成重載。

此時main函數(shù)中調(diào)用則可以正確的調(diào)用到各自的函數(shù)。

但是請看main函數(shù)中被注釋掉的一句代碼。如果我將它放出來,則會提出警告:將double類型轉(zhuǎn)換成int類型可能會丟失數(shù)據(jù)。這就意味著我們編譯器針對下面兩句調(diào)用都調(diào)用了參數(shù)類型int的compare。由此可見,編譯器調(diào)用函數(shù)時優(yōu)先在局部作用域搜索,若搜索成功則全部按照該函數(shù)的標準調(diào)用。若未搜索到才在全局作用域進行搜索。

總結(jié):C語言不存在函數(shù)重載,C++根據(jù)函數(shù)名參數(shù)個數(shù)參數(shù)類型判斷重載,屬于靜多態(tài),必須同一作用域下才叫重載。

const

這一部分非常重要。在我的另一篇博客“C語言的32個關(guān)鍵字”中對C語言中的const也有所講解。當中提到了這么一個問題:C語言中被const修飾的變量不是常量,叫做常變量或者只讀變量,這個常變量是無法當作數(shù)組下標的。然而在C++中const修飾的變量可以當作數(shù)組下標使用,成為了真正的常量。這就是C++對const的擴展。

C語言中的const:被修飾后不能做左值,可以不初始化,但是之后沒有機會再初始化。不可以當數(shù)組的下標,可以通過指針修改。簡單來說,它和普通變量的區(qū)別只是不能做左值而已。其他地方都是一樣的。

C++中的const:真正的常量。定義的時候必須初始化,可以用作數(shù)組的下標。const在C++中的編譯規(guī)則是替換(和宏很像),所以它被看作是真正的常量。也可以通過指針修改。需要注意的是,C++的指針有可能退化成C語言的指針。比如以下情況:

int b = 20;
const int a = b;

這時候的a就只是一個普通的C語言的const常變量了,已經(jīng)無法當數(shù)組的下標了。(引用了一個編譯階段不確定的值)

const在生成符號時,是local符號。即在本文件中才可見。如果非要在別的文件中使用它的話,在文件頭部聲明:extern cosnt int data = 10;這樣生成的符號就是global符號。

總結(jié):C中的const叫只讀變量,只是無法做左值的變量;C++中的const是真正的常量,但也有可能退化成c語言的常量,默認生成local符號。

引用

說到引用,我們第一反應(yīng)就是想到了他的兄弟:指針。引用從底層來說和指針就是同一個東西,但是在編譯器中它的特性和指針完全不同。

int a = 10;
int &b = a;
int*p=&a;
//b = 20;
//*p = 20;

首先定義一個變量a = 10,然后我們分別定義一個引用b以及一個指針p指向a。我們來轉(zhuǎn)到反匯編看看底層的實現(xiàn):

圖片

可以看到底層實現(xiàn)完全一致,取a的地址放入eax寄存器,再將eax中的值存入引用b/指針p的內(nèi)存中。至此我們可以說(在底層)引用本質(zhì)就是一個指針。了解了底層實現(xiàn),我們回到編譯器。我們看到對a的值的修改,指針p的做法是*p = 20;即進行解引用后替換值。底層實現(xiàn):

圖片

再來看看引用修改:

圖片

我們看到修改a的值的方法也是一樣的,也是解引用。只是我們在調(diào)用的時候有所不同:調(diào)用p時需要*p解引用,b則直接使用就可以。由此我們推斷出:引用在直接使用時是指針解引用。p直接使用則是它自己的地址。這樣我們也了解了,我們給引用開辟的這塊內(nèi)存是根本訪問不到的。如果直接用就直接解引用了。即使打印&b,輸出的也是a的地址。

注:"*"的作用是引用指針指向的變量值,引用其實就是引用該變量的地址,“解”就是把該地址對應(yīng)的東西解開,解出來,就像打開一個包裹一樣,那就是該變量的值了,所以稱為“解引用”。也就是說,解引用是返回內(nèi)存地址中對應(yīng)的對象。

在此附上將指針轉(zhuǎn)為引用的小技巧:

int*p=&a
/*我們將引用符號移到左邊將*替換即可:*/
int&p=a

接下來看看如何創(chuàng)建數(shù)組的引用:

int array[10] = {0};//定義一個數(shù)組

我們知道,array拿出來使用的話就是數(shù)組array的首元素地址。即是int *類型。那么&array是什么意思呢?int **類型,用來指向array[0]地址的一個地址嗎?不要想當然了,&array是整個數(shù)組類型。

那么要定義一個數(shù)組引用,按照上面的小訣竅,先來寫寫數(shù)組指針吧:

int (*q) [10] = &array;

將右側(cè)的&對左邊的*進行覆蓋:

int (&q)[10] = array;

測試sizeof(q) = 10。我們成功創(chuàng)建了數(shù)組引用。經(jīng)過上面的詳解 ,我們知道了引用其實就是取地址。那么我們都知道一個立即數(shù)是沒有地址的,即

int &b = 10;

這樣的代碼是無法通過編譯的。那如果你就是非要引用一個立即數(shù),其實也不是沒有辦法:

const int &b  = 10;

即將這個立即數(shù)用const修飾一下,就可以了。為什么呢?

這時因為被const修飾的都會產(chǎn)生一個臨時量來保存這個數(shù)據(jù),自然就有地址可取了。

總結(jié):引用底層就是指針,使用時會直接解引用,可以配合const對一個立即數(shù)進行引用。

malloc,free && new,delete

這個問題很有意思,也是重點需要關(guān)注的問題。malloc()和free()是C語言中動態(tài)申請內(nèi)存和釋放內(nèi)存的標準庫中的函數(shù)。而new和delete是C++運算符、關(guān)鍵字。new和delete底層其實還是調(diào)用了malloc和free。它們之間的區(qū)別有以下幾個方面:

①:malloc和free是函數(shù),new和delete是運算符。

②:malloc在分配內(nèi)存前需要大小,new不需要。

例如:

int *p1 = (int *)malloc(sizeof(int));
int *p2 = new int;     //int *p3 = new int(10);

malloc時需要指定大小,還需要類型轉(zhuǎn)換。new時不需要指定大小因為它可以從給出的類型判斷,并且還可以同時賦初始值。

③:malloc不安全,需要手動類型轉(zhuǎn)換,new不需要類型轉(zhuǎn)換。

詳見上一條。

④:free只釋放空間,delete先調(diào)用析構(gòu)函數(shù)再釋放空間(如果需要)。

與第⑤條對應(yīng),如果使用了復雜類型,先析構(gòu)再call operator delete回收內(nèi)存。

⑤:new是先調(diào)用構(gòu)造函數(shù)再申請空間(如果需要)。

與第④條對應(yīng),我們在調(diào)用new的時候(例如int *p2 = new int;這句代碼 ),底層代碼的實現(xiàn)是:首先push 4字節(jié)(int類型的大?。S后call operator new函數(shù)分配了內(nèi)存。由于我們這句代碼并未涉及到復雜類型,如類類型,所以也就沒有構(gòu)造函數(shù)的調(diào)用。如下是operator new的源代碼,也是new實現(xiàn)的重要函數(shù):

void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{       // try to allocate size bytes
void *p;
while ((p = malloc(size)) == 0)
if (_callnewh(size) == 0)
{       // report no memory
_THROW_NCEE(_XSTD bad_alloc, );
}
return (p);
}

我們可以看到,首先malloc(size)申請參數(shù)字節(jié)大小的內(nèi)存。

如果失敗(malloc失敗返回0)則進入判斷:

如果_callnewh(size)也失敗的話,拋出bad_alloc異常。

_callnewh()這個函數(shù)是在查看new handler是否可用。

如果可用會釋放一部分內(nèi)存再返回到malloc處繼續(xù)申請。

如果new handler不可用就會拋出異常。

⑥:內(nèi)存不足(開辟失?。r處理方式不同。

malloc失敗返回0,new失敗拋出bad_alloc異常。

⑦:new和malloc開辟內(nèi)存的位置不同。

malloc開辟在堆區(qū),new開辟在自由存儲區(qū)域。

⑧:new可以調(diào)用malloc(),但malloc不能調(diào)用new。

new就是用malloc()實現(xiàn)的,new是C++獨有malloc當然無法調(diào)用。

作用域

C語言中作用域只有兩個:局部,全局。C++中則是有:局部作用域,類作用域,名字空間作用域三種。

所謂名字空間就是namespace,我們定義一個名字空間就是定義一個新作用域。訪問時需要以如下方式訪問,以std為例:

std::cin<< "123" <

例如我們有一個名字空間叫Myname,其中有一個變量叫做data。如果我們希望在其他地方使用data的話,需要在文件頭聲明:using Myname::data;這樣一來data就使用的是Myname中的值了。可是這樣每個符號我們都得聲明豈不是累死?我們只要using namespace Myname;就可以將其中所有符號導入了。所以我們經(jīng)??吹饺缦麓a:

using namespace std;

審核編輯:湯梓紅
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • C語言
    +關(guān)注

    關(guān)注

    180

    文章

    7604

    瀏覽量

    136683
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4327

    瀏覽量

    62569
  • C++
    C++
    +關(guān)注

    關(guān)注

    22

    文章

    2108

    瀏覽量

    73618
  • 編譯器
    +關(guān)注

    關(guān)注

    1

    文章

    1623

    瀏覽量

    49107
收藏 人收藏

    評論

    相關(guān)推薦

    C語言和C++哪一個更好用

    在嵌入式軟件程序開發(fā),C語言無疑是最常被使用的程序語言。不過應(yīng)該明白的是,有些嵌入式硬件同時提供C語言
    發(fā)表于 11-08 07:46

    C語言和C++編程的一些思考資料說明

    最原始的方式對函數(shù)進行命名。學過編譯原理的同學就會知道,最原始的C++編譯器其實就是將C++轉(zhuǎn)化成C語言,然后用C
    發(fā)表于 05-09 18:16 ?1次下載
    <b class='flag-5'>C</b><b class='flag-5'>語言和</b><b class='flag-5'>C++</b>編程的一些思考資料說明

    MATLAB 64位C語言和C++編譯器應(yīng)用程序免費下載

    本文檔的主要內(nèi)容詳細介紹的是MATLAB 64位C語言和C++編譯器應(yīng)用程序免費下載。
    發(fā)表于 05-21 08:00 ?4次下載
    MATLAB 64位<b class='flag-5'>C</b><b class='flag-5'>語言和</b><b class='flag-5'>C++</b>編譯器應(yīng)用程序免費下載

    C++語言和面向?qū)ο蟪绦蛟O(shè)計教程

    C++語言和面向?qū)ο蟪绦蛟O(shè)計代表了旨在使計算機問題解更加符合人的思維活動,是軟件開發(fā)方法的一場革命;面向?qū)ο蠼:兔嫦驅(qū)ο笤O(shè)計與實現(xiàn)在軟件開發(fā)生命周期中起著關(guān)鍵作用。 全書共有14章和一個附錄。第1
    發(fā)表于 03-02 08:00 ?6次下載

    使用C語言和C++編寫俄羅斯方塊的資料和源代碼免費下載

    本文檔的主要內(nèi)容詳細介紹的是使用C語言和C++編寫俄羅斯方塊的資料和源代碼免費下載。
    發(fā)表于 06-10 08:00 ?4次下載
    使用<b class='flag-5'>C</b><b class='flag-5'>語言和</b><b class='flag-5'>C++</b>編寫俄羅斯方塊的資料和源代碼免費下載

    詳談C語言和C++的區(qū)別和聯(lián)系

    在學習了C語言和C++之后,這兩者之間的區(qū)別我們需要仔細的捋一捋!
    的頭像 發(fā)表于 06-29 14:56 ?5757次閱讀
    詳談<b class='flag-5'>C</b><b class='flag-5'>語言和</b><b class='flag-5'>C++</b>的區(qū)別和聯(lián)系

    CC++是一回事嗎

    C89,C++標準是C++99。 我們來介紹C語言和C++
    的頭像 發(fā)表于 11-13 18:18 ?3283次閱讀

    C語言和C++的特點與用法詳細說明

    本文檔的主要內(nèi)容詳細介紹的是C語言和C++的特點與用法詳細說明。
    的頭像 發(fā)表于 12-26 10:58 ?4403次閱讀

    嵌入式程序開發(fā),C語言和C++究竟應(yīng)該用哪個?

    在嵌入式軟件程序開發(fā),C語言無疑是最常被使用的程序語言。不過應(yīng)該明白的是,有些嵌入式硬件同時提供C語言
    發(fā)表于 11-03 14:21 ?60次下載
    嵌入式程序開發(fā),<b class='flag-5'>C</b><b class='flag-5'>語言和</b><b class='flag-5'>C++</b>究竟應(yīng)該用哪個?

    C語言C++面試知識點總結(jié)

    相對而言,C語言和C++相關(guān)的面試題比較少見,沒有Java方向?qū)懙娜四敲炊啵@是一篇 C 語言C++
    的頭像 發(fā)表于 05-12 14:59 ?1453次閱讀

    C語言C++面試知識點總結(jié)

    相對而言,C語言和C++相關(guān)的面試題比較少見,沒有Java方向?qū)懙娜四敲炊?,這是一篇 C 語言C++
    的頭像 發(fā)表于 05-13 11:59 ?1856次閱讀

    C語言和C++到底是什么關(guān)系

    首先C++C語言本來就是兩種不同的編程語言,但C++確實是對C
    的頭像 發(fā)表于 06-20 11:28 ?4947次閱讀

    如何選擇創(chuàng)建c語言和c++

    選擇創(chuàng)建 C 語言和 C++ 都需要綜合考慮多個因素。在決定使用哪種語言之前,我們需要對這兩種語言的特點、優(yōu)缺點、適用場景、學習成本等進行全
    的頭像 發(fā)表于 11-27 15:58 ?599次閱讀

    vb語言和c++語言的區(qū)別

    VB語言和C++語言是兩種不同的編程語言,雖然它們都屬于高級編程語言,但在設(shè)計和用途上有很多區(qū)別。下面將詳細比較VB
    的頭像 發(fā)表于 02-01 10:20 ?2252次閱讀

    C語言和C++結(jié)構(gòu)體的區(qū)別

    同樣是結(jié)構(gòu)體,看看在C語言和C++中有什么區(qū)別?
    的頭像 發(fā)表于 10-30 15:11 ?197次閱讀
    RM新时代网站-首页