C++函數重載實現的原理以及為什麼在C++中調用C語言編譯的函數時要加上extern "C"聲明

来源:http://www.cnblogs.com/kj1501120706/archive/2017/07/02/7107172.html
-Advertisement-
Play Games

C++相對於C語言而言支持函數重載是其極大的一個特點,相信在使用C語言的時候大家如果要寫一個實現兩個整型數據相加的函數還要寫一個浮點型數據相加的函數,那麼這兩個函數的名字絕對不可以一樣,這樣無疑在我們使用這個函數的時候增加了複雜性,但是在C++中我們卻可以很好的解決這個問題,因為在C++中函數是支持 ...


        C++相對於C語言而言支持函數重載是其極大的一個特點,相信在使用C語言的時候大家如果要寫一個實現兩個整型數據相加的函數還要寫一個浮點型數據相加的函數,那麼這兩個函數的名字絕對不可以一樣,這樣無疑在我們使用這個函數的時候增加了複雜性,但是在C++中我們卻可以很好的解決這個問題,因為在C++中函數是支持重載的也就是說兩個函數的函數名可以一樣,這樣並不會出現函數名重定義的問題,但是我們在使用的時候也要遵守一些規定,這些規定我們會在接下來的討論中提到,下麵我們就來分析在C++中函數是如何實現函數的重載的。

在這裡我們用C語言和C++分別寫兩個函數,通過函數的符號表來觀察函數名在經過編譯之後究竟是什麼形式的

下麵就是我們的測試代碼:

 1 #include<iostream>
 2 
 3 using namespace std;
 4 
 5 
 6 
 7 int Add(int x, int y)
 8 
 9 {
10 
11 int z = 0;
12 
13 z = x + y;
14 
15 return z;
16 
17 }
18 
19 
20 
21 double Add(double x, double y)
22 
23 {
24 
25 double z = 0;
26 
27 z = x + y;
28 
29 return z;
30 
31 }
32 
33  
34 
35 int main()
36 
37 {
38 
39 cout<<Add(1,3)<<endl;
40 
41 cout<<Add(1.5,3.5)<<endl;
42 
43 return 0;
44 
45 }

 

VS2008的編譯環境下:

我們生成.map文件,然後可以查看函數在經過編譯之後的函數名稱為下圖所示:

 

 

 

不難發現上圖中函數命名的一些規律(當然這個規律只是片面的針對於VS2008編譯環境):

1.以“?”開始和以”@Z”結尾

2.函數的名稱緊接“?”之後

3.在函數明德後面分別是函數返回值類型修飾符、參數列表中的參數的類型修飾符

 

下麵我們把這個相同的函數改為c語言的代碼

代碼如下:

 

 1 //#include<iostream>
 2 
 3 //using namespace std;
 4 
 5 #include<stdio.h>
 6 
 7  
 8 
 9  
10 
11 int Add(int x, int y)
12 
13 {
14 
15 int z = 0;
16 
17 z = x + y;
18 
19 return z;
20 
21 }
22 
23  
24 
25 double Add(double x, double y)
26 
27 {
28 
29 double z = 0;
30 
31 z = x + y;
32 
33 return z;
34 
35 }
36 
37  
38 
39 int main()
40 
41 {
42 
43 //cout<<Add(1,3)<<endl;
44 
45 //cout<<Add(1.5,3.5)<<endl;
46 
47 return 0;
48 
49 }

 

這時我們編譯的話就會出現錯誤:

 

 

 

這裡告訴我們函數名出現重定義

那麼這是為什麼呢?

這時我們註釋掉一個函數然後編譯後查看.map文件,查看函數重命名之後的名稱

 

 

 

 

這裡我們可以發現函數在編譯之後重命名的名稱僅僅只是在函數名稱的前面加上了一個"_"(下劃線),這樣我們就不難分析了,C和C++編譯的時候對函數的重命名機制是完全不一樣的

1.C語言中僅僅只是在函數的名稱的前面加上了"_"(下劃線)

2.C++有自己的命名修飾規則,他會根據函數的參數列表中變數的類型等進行相應的類型修飾

 雖然C++支持函數的重載但是我們在使用的時候也要註意以下幾點:

1.函數的重載只是出現在同一作用域,例如假如兩個工程里的函數名稱相同,但是他們也不是函數的重載

2.函數名相同,函數的參數列表不同,返回值可同可不同,為什麼函數返回值可同可不同呢?

這是因為在不同的編譯環境下對於函數名稱的修飾並不是相同的,下麵就是在Linux環境下函數編譯後重命名的形式:

 

 

仔細觀察不難發現在Linux環境下的函數重命名的一些規則:

1.以“_Z”z作為開頭,緊隨其後的數字是函數名稱的單詞的個數

2.函數的名稱後面有函數的參數列表中參數的類型修飾符,i是int型,d是double型

通過以上的闡述相信大家可以對C++中為什麼可以實現函數重載有了清晰的認識,那麼我們也就不難回答為什麼在C++中調用被C編譯過後的函數應該在前面加上 extern "C" 聲明瞭。

       這是因為我們當前是處於c++語言環境,這個時候我們如果不指定要調用的那個函數是用C語言編譯的函數,那麼當前在C++文件中編譯時就會報錯說是該函數是一個無法解析的外部符號,因為在編譯運行的時候我們當前的程式會從符號表中去找相應的函數名,可是C++和C編譯後生成的符號表中函數的名是不同的,那麼這個函數也就是一個無法解析的外部符號了,但是當你用extern “C” 指明該函數是用C語言編譯的函數,那麼當前代碼在編譯運行的時候就會從用C語言編譯的那個符號表文件中去查找相應的函數名,這樣整個程式的編譯運行費也就沒有問題了。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 本文分析了HashMap的實現原理,以及resize可能引起死迴圈和Fast-fail等線程不安全行為。同時結合源碼從數據結構,定址方式,同步方式,計算size等角度分析了JDK 1.7和JDK 1.8中ConcurrentHashMap的實現原理。 ...
  • 【面向對象基礎】【封裝和繼承】【PHP關鍵字】【單例】【對象串列化和魔術方法】【抽象類和抽象方法】【介面與多態】 ...
  • 不解釋,直接上代碼: ...
  • 為了更好的備戰NOIP2013,電腦組的幾個女孩子LYQ,ZSC,ZHQ認為,我們不光需要機房,我們還需要運動,於是就決定找校長申請一塊電腦組的課餘運動場地,聽說她們都是電腦組的高手,校長沒有馬上答應他們,而是先給她們出了一道數學題,並且告訴她們:你們能獲得的運動場地的面積就是你們能找到的這個最大的 ...
  • 題目描述 在平面上有 n 個點(n <= 50),每個點用一對整數坐標表示。例如:當 n=4 時,4個點的坐標分另為:p1(1,1),p2(2,2),p3(3,6),P4(0,7),見圖一。 這些點可以用 k 個矩形(1<=k<=4)全部覆蓋,矩形的邊平行於坐標軸。當 k=2 時,可用如圖二的兩個矩 ...
  • 1.什麼是面向對象 面向對象(oop)是一種抽象的方法來理解這個世界,世間萬物都可以抽象成一個對象,一切事物都是由對象構成的。應用在編程中,是一種開發程式的方法,它將對象作為程式的基本單元。 2.面向對象與面向過程的區別 我們之前已經介紹過面向過程了http://www.cnblogs.com/zh ...
  • 網站爬蟲,主要是爬博客http://www.cnblogs.com/xxxx下的所有文章內容及標題,保存到data目錄下。具體如下: ...
  • 共用模式acquire實現流程 上文我們講解了AbstractQueuedSynchronizer獨占模式的acquire實現流程,本文趁熱打鐵繼續看一下AbstractQueuedSynchronizer共用模式acquire的實現流程。連續兩篇文章的學習,也可以對比獨占模式acquire和共用模 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...