<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # [32] 如何混合C和C++編程 ## FAQs in section [32]: * [32.1] 混合C和C++編程時我需要知道什么? * [32.2] 如何在C++代碼中包含標準的C頭文件? * [32.3] 如何在C++代碼中包含非系統的C頭文件? * [32.4] 如何修改我自己的C頭文件 , 以便更容易的在C++代碼中包含他們? * [32.5] 如何從C++代碼中調用非系統C 函數f(int,char和float)? from my C++ code?") * [32.6] 如何創建一個C++ 函數f(int,char和float),可以由我的C代碼調用? that is callable by my C code?") * [32.7] 為什么鏈接器報錯說C / C++函數調用C++ / C函數? * [32.8] 如何傳遞一個C++ 類對象從/到一個C函數? * [32.9] 我的C函數可以直接訪問一個C++ 對象的數據嗎? * [32.10] 為什么C++而不是為C讓我覺得“更加遠離機器”? ## 32.1 混合C和C++編程時我需要知道什么? 以下是一些要點(雖然有些編譯器供應商可能不需要全部要點,查看你的編譯器供應商的文檔): * 你必須使用你的C++編譯器來編譯的main()(也就是說靜態初始化) * 你的C++編譯器應該能夠進行直接鏈接(也就是說,它有自己的專門類庫) * 你的C和C++編譯器可能需要來自同一個供應商,并具有兼容的版本(也就是說,它們有相同的調用約定) 此外,您需要閱讀本節的其余部分,了解如何使你的C可調用的C++函數和/或C++可調用C函數。 順便說一下,還有另一種途徑來處理這件事:使用C++編譯器編譯所有代碼(甚至是你的C風格代碼)。這幾乎無需混合C和C++,但是你要格外小心(也可能是,希望! -發現了一些錯誤)你的C風格的代碼。缺點是你需要更新你的C代碼風格,主要是因為C++編譯器比C編譯器更加嚴謹/挑剔。值得一提的是,清理你的C代碼風格可能會比實際混合C和C++所付出的努力要少,并且清理C代碼風格還能給你帶來一份額外收入。但是很明顯,你幾乎沒有選擇的余地,如果你不能改變C代碼(例如,如果它是來自第三方的)。 ## 32.2 如何在C++代碼中包含標準的C頭文件? 要包含一個標準(如`<cstdio>`)頭文件,你不需要做任何事情。例如: ``` //?This?is?C++?code ?#include?<cstdio>????????????????//?Nothing?unusual?in?#include?line ?int?main() ?{ ???std::printf("Hello?world\n");??//?Nothing?unusual?in?the?call?either ... ?} ``` 如果你認為`std::printf`的`std`部分很奇怪,那么最好的辦法是“適應它”。換句話說,它是使用標準庫函數的標準方法,所以你不妨現在開始習慣它。 然而,如果你正在使用你的C++編譯器編譯C代碼,你恐怕不想修改所有這些`printf`調用為`std::printf` 。幸運的是,這種情況下,C代碼將使用舊式頭`<stdio.h>`而不是新型頭`<cstdio>`,命名空間技術將會照顧一切: ``` /*?This?is?C?code?that?I'm?compiling?using?a?C++?compiler?*/ ?#include?<stdio.h>??????????/*?Nothing?unusual?in?#include line?*/ ?int?main() ?{ ???printf("Hello?world\n");??/*?Nothing?unusual?in?the?call?either?*/ ... ?} ``` 最后的評論:如果你有不屬于標準庫C頭文件,你需要遵守一些不同的準則。有兩種情況:要么你不能改變頭文件,要么你可以改變頭文件。 ## 32.3 如何在C++代碼中包含非系統的C頭文件? 如果你是其中一個C頭文件不是由系統提供的,你可能需要把`#include`行放到`extern"C"(/ * ... * /)`構造中。這告訴C++編譯器的功能在頭文件中聲明的C函數。 ``` //?This?is?C++?code ?extern?"C"?{ //?Get?declaration?for?f(int?i,?char?c,?float?x) ???#include?"my-C-code.h" ?} ?int?main() ?{ ???f(7,?'x',?3.14);???//?Note:?nothing?unusual?in?the?call ... ?} ``` 注: 對于系統提供的C頭文件(如`<cstdio>`)和你可以更改的C頭文件,準則略有不同 ## 32.4 如何修改我自己的C頭文件 , 以便更容易的在C++代碼中包含他們? 如果你包含了不是由系統提供的C頭文件,并且如果你能夠改變的C頭文件,你應該著重考慮通過添加 `extern"C"(...)`塊到頭文件,這樣使C++用戶在C++代碼中更容易使用`#include`。由于C編譯器通不過頭文件含有 `extern"C"`的結構,你需要把`extern"C"{}`行包裹在`#ifdef`預編譯塊中,這樣他們不會被正常的C編譯器編譯。 步驟#1:將以下行添加到你C頭文件的頂部(注:符號`__cplusplus `當且僅當編譯器是C++編譯器的時候被定義): ``` ?#ifdef?__cplusplus ?extern?"C"?{ ?#endif ``` 步驟#2:將以下行添加到你C頭文件的最底部: ``` ?#ifdef?__cplusplus ?} ?#endif ``` 現在您可以`#include`你的C頭文件,不用在C++代碼包含任何的`EXTERN "C"`: ``` //?This?is?C++?code //?Get?declaration?for?f(int?i,?char?c,?float?x) ?#include?"my-C-code.h"???//?Note:?nothing?unusual?in?#include?line ?int?main() ?{ ???f(7,?'x',?3.14);???????//?Note:?nothing?unusual?in?the?call ... ?} ``` 注: 對于系統提供的C頭文件(如`<cstdio>`)和你可以更改的C頭文件,準則略有不同 注:`#define`宏有4中罪惡: 罪惡#1 , 罪惡#2 , 罪惡#3 和罪惡#4 。但有時他們仍然有用。只要別忘了使用后洗清“罪惡”的雙手。 ## 32.5 如何從C++代碼中調用非系統C 函數`f`(`int`,`char`和`float`)? 如果你有一個個人的C函數要調用,由于一些其他原因,你沒有或不想在函數聲明中`#include`一個 C頭文件,你可以在C++代碼通過`extern"C"`語法聲明單個的C函數。當然,你需要使用完整的函數原型: ``` extern?"C"?void?f(int?i,?char?c,?float?x); ``` 可以使用大括號聲明幾個C函數: ``` ?extern?"C"?{ ???void???f(int?i,?char?c,?float?x); ???int????g(char*?s,?const?char*?s2); ???double?sqrtOfSumOfSquares(double?a,?double?b); ?} ``` 在此之后你可以象調用C++函數那樣調用該函數: ``` ?int?main() ?{ ???f(7,?'x',?3.14);???//?Note:?nothing?unusual?in?the?call ... ?} ``` ## 32.6 如何創建一個C++ 函數`f`(`int`,`char`和`float`),可以由我的C代碼調用? 通過使用`EXTERN的"C"`結構通知C++編譯器`f(int,char,float)`可由一個C編譯器調用 : ``` //?This?is?C++?code //?Declare?f(int,char,float)?using?extern?"C": ?extern?"C"?void?f(int?i,?char?c,?float?x); ... //?Define?f(int,char,float)?in?some?C++?module: ?void?f(int?i,?char?c,?float?x) ?{ ... ?} ``` 通過`extern"C"`行告訴編譯器應該使用C調用約定和名字校正(name mangling)(例如,以下劃線開頭)來進行鏈接。由于C不支持重載,所以你不能編寫可以由C程序調用的重載函數。 ## 32.7 為什么鏈接器報錯說C / C++函數調用C++ / C函數? 如果你沒有設置對`EXTERN`的`"C"`,你有時會得到鏈接錯誤,而不是編譯器錯誤。這是由于C++編譯器通常是“校正(mangle)”函數名稱(例如,為了支持函數重載),這和C編譯器不同。 關于如何使用`EXTERN`的 `"C"`請參考前兩個的FAQs。 ## 32.8 如何傳遞一個C++ 類對象從/到一個C函數? 下面是一個例子(關于`extern"C"`,見前面的兩個FAQs)。 ``` //Fred.h: /*?This?header?can?be?read?by?both?C?and?C++?compilers?*/ ?#ifndef?FRED_H ?#define?FRED_H ?#ifdef?__cplusplus ???class?Fred?{ ???public: ?????Fred(); ?????void?wilma(int); ???private: ?????int?a_; ???}; ?#else ???typedef ?????struct?Fred ???????Fred; ?#endif ?#ifdef?__cplusplus ?extern?"C"?{ ?#endif ?#if?defined(__STDC__)?||?defined(__cplusplus) ???extern?void?c_function(Fred*);???/*?ANSI?C?prototypes?*/ ???extern?Fred*?cplusplus_callback_function(Fred*); ?#else ???extern?void?c_function();????????/*?K&R?style?*/ ???extern?Fred*?cplusplus_callback_function(); ?#endif ?#ifdef?__cplusplus ?} ?#endif ?#endif?/*FRED_H*/ // Fred.cpp: //?This?is?C++?code ?#include?"Fred.h" ?Fred::Fred()?:?a_(0)?{?} ?void?Fred::wilma(int?a)?{?} ?Fred*?cplusplus_callback_function(Fred*?fred) ?{ ???fred->wilma(123); ???return?fred; ?} //main.cpp: //?This?is?C++?code ?#include?"Fred.h" ?int?main() ?{ ???Fred?fred; ???c_function(&fred); ... ?} //c-function.c /*?This?is?C?code?*/ ?#include?"Fred.h" ?void?c_function(Fred*?fred) ?{ ???cplusplus_callback_function(fred); ?} ``` 不像C++代碼,C代碼將無法告訴你兩個指針是否指向同一個對象,除非指針完全相同。例如,在C++可以很容易地檢查一個派生類`Derived*`指針`dp`和`Base*`指針`bp`是否指向同一個對象,你可以使用`if(dp == bp)`。C++編譯器自動轉換指針為相同的類型,在這種情況下,轉換為`Base*`,然后比較他們。根據不同的C++編譯器的實現細節,這種轉換有時會改變一個指針值的位數據(bits)。但是C編譯器不會知道該怎么做指針轉換,所以比如從`Derived*`到`Base*`的轉換,必須在由C++編譯器的編譯的代碼中,而不是在C編譯器編譯的C代碼中。 _注意:你必須特別小心轉換為`void*`指針,因為該轉換將不會允許__C__或__C++__編譯器做適當的指針調整!例如(繼續前段內容),如果你把`dp`和`bp`賦值到兩個`void *`指針比如說是`dpv`和`bpv`,有可能`dpv != bpv`即使`dp==bp `。不要說我沒有提醒你!_ ## 32.9 我的C函數可以直接訪問一個C++ 對象的數據嗎? 有時。 (有關傳遞C+ + 對象到/從C函數的基本內容,閱讀以前的FAQ)。 你可以安全地從C函數訪問C++對象的數據,如果C++類: * 沒有虛函數(包括繼承虛函數) * 它的所有數據在相同的訪問級別(私有/保護/公共) * 虛函數沒有完全包含的子對象 C++類有任何基類(或任何完全包含子對象具有基類),訪問數據將在技術上是不可移植的,因為繼承體系下的類的布局與語言無關。然而在實踐中,所有C++編譯器都使用相同的方式:首先是基類對象(多重繼承按照左到右的順序),然后是成員對象。 此外,如果類(或任何基類)含有虛函數,幾乎所有C++編譯器給對象添加一個 `void *`,在第一個虛擬函數的位置或在對象的開始位置。同樣,這也不是語言要求的,但幾乎所有的編譯器都是這樣實現的。 如果類有任何虛基類,這將更復雜,更不便于移植。一個常見的實現技術是,在對象的最后位置放置一個虛基類對象( `v` )(無論`v`在繼承層次結構中的位置)。對象的其它部分按照正常順序布局。每一個虛基類`v`的派生類,實際上都有一個指向`v`的指針 。 ## 32.10 為什么C++而不是為C讓我覺得“更加遠離機器”? 因為你就是。 作為一個面向對象編程語言,C++允許你對問題域建模,這將允許你使用問題域的語言編程,而不是解決方案域的語言。 C的優勢之一是,它已“沒有任何隱藏的機制”:所見即所得。你可以閱讀一個 C程序,“看到”每個時鐘周期。在C++中可不是這樣,老的C程序員(如我們許多人曾經是),對于這個特性往往會很矛盾(也許是“敵視”?)。但當他們轉變到面向對象思想以后,他們往往認識到,雖然C++的隱藏一些機制,但是它也提供了更高的抽象和更簡潔的表達,從而能夠在保持運行時性能的同時降低后期維護成本。 當然你可能會編寫糟糕的代碼不管使用任何語言,C++并不保證好的質量,可重用性,抽象,或任何“優異的”測試指標。 _C++中無法阻止糟糕的程序員編寫的糟糕的程序,但是它能夠讓優秀的開發人員創建出色的軟件。_
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看