小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

如何混合使用C和C(上)

 Delores 2007-09-24
何混合使用C和C++(上)     CSDN Blog推出文章指數(shù)概念,文章指數(shù)是對(duì)Blog文章綜合評(píng)分后推算出的,綜合評(píng)分項(xiàng)分別是該文章的點(diǎn)擊量,回復(fù)次數(shù),被網(wǎng)摘收錄數(shù)量,文章長度和文章類型;滿分100,每月更新一次。
 
[32] How to mix C and C++ 如何混合使用CC++
(Part of
C++ FAQ Lite, Copyright © 1991-2006, Marshall Cline, cline@)
Translator: Qiu Longbin <robin.qiu(at)yeah.net>
 
FAQs in section [32]:
 
[32.1] 混合使用CC++代碼時(shí)我需要知道什么?
下面是是一些要點(diǎn)(盡管一些編譯器廠商可能并不需要所有這些;請(qǐng)檢查你的編譯器廠商的文檔):
·       你必須使用你的C++編譯器編譯你的main()(例如,靜態(tài)初始化)
·       你應(yīng)該用C++編譯器接管鏈接過程(例如,這樣可以獲得它的特別的庫)
·       你的CC++編譯器可能需要來自于相同的廠商,并且是兼容的版本(這樣,它們才具備相同的調(diào)用約定)
另外,你應(yīng)該需要繼續(xù)閱讀本文剩下的部分,找出如何才能在C++中調(diào)用C函數(shù)和/或如何在C中調(diào)用C++函數(shù)。
BTW ?也有另一個(gè)途徑來處理這一整個(gè)事情,即:用一個(gè)C++編譯器來了編譯你所有的代碼(甚至是你的C風(fēng)格代碼)。那樣,相當(dāng)程度上就排除了混合CC++的需要,加上它將使得你得在你的C風(fēng)格代碼中更細(xì)心(并且更可能希望如此!發(fā)現(xiàn)一些bugs)。下面(down-side)你需要以某種方式升級(jí)你的C風(fēng)格代碼,這基本上是由于C++編譯器比C編譯器更仔細(xì)/更挑剔的原因。關(guān)鍵是清除你的C風(fēng)格代碼所需的努力可能少于混合CC++,并且額外的好處是你清除了你的C風(fēng)格代碼。顯然,如果你不能改變你的C風(fēng)格代碼,你無需多種選擇。(比如,C風(fēng)格代碼是來自第三方庫)。
 
[32.2] 如何在C++代碼里include一個(gè)標(biāo)準(zhǔn)C頭文件?
#include 一個(gè)標(biāo)準(zhǔn)頭文件(比如<cstdio>,你通常不必作任何事。比如:
 //  這是C++代碼
 
 #include <cstdio>  
// #inlcude行沒有什么不尋常的

 
 int main()
 {
   std::printf("Hello world\n");  
// 調(diào)用也沒什么不尋常的

   ...

 }
如果你認(rèn)為std::printf()調(diào)用中std::部分不尋常,那么你最好克服它(get over it。這句話的意思是使用標(biāo)準(zhǔn)庫中名字的標(biāo)準(zhǔn)方式,因此,你現(xiàn)在就應(yīng)該習(xí)慣它。
然而,如果你正在使用C++編譯器編譯C代碼,你可能不想把所有的printf()的調(diào)用轉(zhuǎn)換成std::printf()。幸運(yùn)的是,這種情況下C代碼可以使用舊風(fēng)格的頭文件<stdio.h>而不是新風(fēng)格頭文件<cstdio>namespace的怪誕。
 /* 這是C代碼,這里用C++編譯器編譯 */
 
 #include <stdio.h>          
/* #inlcude行沒有什么不尋常的 */

 
 int main()
 {
   printf("Hello world\n");  
/* 調(diào)用也沒什么不尋常的 */

   ...

 }
最后評(píng)論:如果你的C頭文件不是標(biāo)準(zhǔn)庫的一部分,我們?yōu)槟銣?zhǔn)備有稍微不同的方針。存在兩種情況你不能改變頭文件,或者你可以改變頭文件。
 
[32.3] 在我的C++代碼中如何include一個(gè)非系統(tǒng)的C頭文件?
如果你要包含的C頭文件不是由系統(tǒng)提供的,你可以把#include包裹在extern “C” { /* here */ }結(jié)構(gòu)里。這就告訴C++編譯器在頭文件中聲明的函數(shù)是C函數(shù)。
 // 這是C++代碼
 
 extern "C" {
   
// 獲得聲明
f(int i, char c, float x)
   #include "my-C-code.h"
 }
 
 int main()
 {
   f(7, 'x', 3.14);   
// 注意:調(diào)用沒什么特別的

   ...

 }
 
[32.4] 我要如何修改我自己的C頭文件,以使得在C++代碼中更容易地#inlcude它們?
如果你要include一個(gè)不是有系統(tǒng)提供的C頭文件,并且你可以修改這個(gè)C頭文件,你應(yīng)該著重考慮在此頭文件中增加extern “C” {}邏輯,這就能使得對(duì)于C++用戶更容易地把它們包含進(jìn)他們的C++代碼中去。因?yàn)?/span>C編譯器不理解extern “C”結(jié)構(gòu),你必須在#ifdef里面包裹extern “C” {}行,讓它們被C編譯器忽略。
步驟#1:把下面三行放置在你的C頭文件的最頂處(注意:符號(hào)__cplusplus只在編譯器為C++編譯器時(shí)才被定義):
 #ifdef __cplusplus
 extern "C" {
 #endif
步驟#2:把如下三行放置在你的C頭文件的最底部:
 #ifdef __cplusplus
 }
 #endif
現(xiàn)在你可以在你的C++代碼里#includeC頭文件里而無需多余的extern “C”
 //  這是C++代碼
 
 
// 獲得聲明 
f(int i, char c, float x)
 #include "my-C-code.h"   
//  注意:#include 行沒什么特別的

 
 int main()
 {
   f(7, 'x', 3.14);       
//  注意:調(diào)用沒什么特別的

   ...

 }
注意:#include4中不同方式下是有缺陷(evil)的:evil#1[1] , evil#2[2] , evil#3[3] , andevil#4。但是,它們常常仍很有用。
 
 
[32.5] 我如何才能在我的C++代碼中調(diào)用一個(gè)非系統(tǒng)的C函數(shù)f(int, char, float)?
如果你有一個(gè)獨(dú)立的C函數(shù)想調(diào)用,并且,由于一些原因,你不能或不想#include那個(gè)聲明有此函數(shù)的頭文件,你可以在你的C++代碼里使用extern “C”語法聲明這個(gè)獨(dú)立的C函數(shù)。很自然,你需要使用函數(shù)的完全形式的原型:
 extern "C" void f(int i, char c, float x);
多個(gè)C函數(shù)可以通過大括號(hào)被成組放在一個(gè)塊中。
 extern "C" {
   void   f(int i, char c, float x);
   int    g(char* s, const char* s2);
   double sqrtOfSumOfSquares(double a, double b);
 }
這之后,你只需把它們當(dāng)作C++函數(shù)簡(jiǎn)單地調(diào)用他們就行了:
 int main()
 {
   f(7, 'x', 3.14);   
// 注意:調(diào)用沒什么特別的

   ...

 }
 
 
[32.6] 如何創(chuàng)建一個(gè)C++函數(shù)f(int, char, float),它可以被我的C代碼調(diào)用?
 // 這是C++代碼
 
 
// 使用 
extern "C"聲明 f(int,char,float) :
 extern "C" void f(int i, char c, float x);
 
 
...

 
 
// 在某個(gè)C++模塊中定義 
f(int,char,float):
 void f(int i, char c, float x)
 {
   
...

 }
extern “C”行告知編譯器傳送給鏈接器的外部信息(external information)使用C調(diào)用約定和名字重整(name mangling)規(guī)則(比如,加一個(gè)前綴下劃線)。因?yàn)槊种剌d(name overloading)不被C支持,所以你不能同時(shí)寫幾個(gè)被C程序調(diào)用的重載函數(shù)。
 
 
[32.7] C/C++函數(shù)被C++/C函數(shù)調(diào)用時(shí),為何鏈接器給出錯(cuò)誤信息?
如果你未能正確處理extern “C”,你將得到鏈接錯(cuò)誤而不是編譯錯(cuò)誤。這歸因于這樣一個(gè)事實(shí):C++編譯器在函數(shù)名重整(mangle)方面與C編譯器常常不同。
請(qǐng)查看前面兩個(gè)關(guān)于如何使用extern “C”FAQ.
 
[32.8] 如何能夠傳遞一個(gè)C++類對(duì)象到/從一個(gè)C函數(shù)?
這里是一個(gè)例子(extern “C”的信息,參見前面兩個(gè)FAQs)。
Fred.h:
 /* 這個(gè)頭文件可以被CC++編譯器讀取 */
 #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:
 // 這是C++代碼
 
 #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:
 // 這是C++代碼
 
 #include "Fred.h"
 
 int main()
 {
   Fred fred;
   c_function(&fred);
   
...

 }
c-function.c:
 /* 這是C代碼 */
 
 #include "Fred.h"
 
 void c_function(Fred* fred)
 {
   cplusplus_callback_function(fred);
 }
不同于你的C++代碼,除非指針是完全一致的類型,否則你的C代碼不能判斷出兩個(gè)指針指向同一個(gè)對(duì)象。比如,在C++中,很容易檢查一個(gè)Derived*的指針dpBase*的指針bp一樣指向了相同的對(duì)象:只要說if (dp == bp ) ...C++編譯器自動(dòng)把兩個(gè)指針轉(zhuǎn)換到相同的類型,在這個(gè)例子中,轉(zhuǎn)換到Base*,然后再比較它們。依賴于C++編譯器的實(shí)現(xiàn)細(xì)節(jié),這個(gè)轉(zhuǎn)換時(shí)常改變了指針值的位(bits)信息。然而,你的C編譯器將不知道如何做那樣的轉(zhuǎn)換,因此,比如從Derived*Base*的轉(zhuǎn)換必須發(fā)生在用C++編譯器編譯的代碼中,而不應(yīng)該在用C編譯的代碼中。
注意:當(dāng)把兩者轉(zhuǎn)換成void*時(shí)你必須特別小心,因?yàn)檫@種轉(zhuǎn)換將不允許CC ++編譯器做適當(dāng)?shù)闹羔樥{(diào)整!例如(接著前面的章節(jié)),你把dpbp都賦值給void*指針dpvbpv,你可能獲得dpv != bpv的情況,即使dp == bp。同時(shí)你會(huì)收到警告信息。
 
[32.9] 我的C函數(shù)可以直接訪問C++類對(duì)象中的數(shù)據(jù)嗎?(譯者:符合“POD”類型,就可以了)
有時(shí)可以。
(傳遞一個(gè)C++類對(duì)象到/從一個(gè)C函數(shù)的基本信息,參見前面的FAQ
你可以安全地從C函數(shù)中訪問C++對(duì)象的數(shù)據(jù),如果C++類滿足下面條件:
·       沒有virtual函數(shù)(包括繼承來的virtual函數(shù))
·       所有數(shù)據(jù)都有處在同一個(gè)訪問級(jí)段中(private/protected/public
·       沒有完全包含(fully-contained,譯注:成員對(duì)象,即包含而非聚合)的帶有virtual函數(shù)的子對(duì)象(subobjects
如果C++類擁有很多基類(或者如果任一完全包含的子對(duì)象有多個(gè)基類),技術(shù)上而言訪問其數(shù)據(jù)是不可移植的,因?yàn)槔^承之下的class布局(layout)上,語言并為強(qiáng)制。但是在實(shí)際上,所有C++編譯器都幾乎以同樣的方式處理:基類對(duì)象第一個(gè)出現(xiàn)(多繼承時(shí)按從左到右的次序),然后是成員對(duì)象。
更進(jìn)一步,如果類(或者任意基類)含有一些virtual函數(shù),幾乎所有的C++編譯器都放置一個(gè)void*在第一個(gè)virtual函數(shù)出現(xiàn)的位置或者在對(duì)象的最前面。還有就是,這些都不是語言要求的,但它是每個(gè)編譯器都采取的方式。
如果類有virtual基類,這就更加復(fù)雜和移植性更差。通用的實(shí)現(xiàn)技術(shù)是讓對(duì)象包含一個(gè)virtual基類對(duì)象(V)(無論V作為virtual基類出現(xiàn)在繼承層次結(jié)構(gòu)的什么地方)。對(duì)象的其余部分以通常的次序出現(xiàn)。每個(gè)派生的含有V作為virtual基類的對(duì)象,實(shí)際上擁有一個(gè)指針,指向最終對(duì)象的V部分。(譯者:更多這方面的信息參見《Inside C++ Object Model》)
 
 
[32.10] 為什么我感覺到相對(duì)于C,在C++中我更遠(yuǎn)離機(jī)器層面
因?yàn)槟愕拇_如此。
作為一個(gè)OO編成語言,C++允許你對(duì)問題域本身建模,這就允許你在問題域語言中編程而不是在解空間(solution domain)編程。
C的一個(gè)強(qiáng)大之處在于它沒有隱藏什么機(jī)制(no hidden mechanism:你所見,即你所得。你可以讀你的C程序并且查看(see每個(gè)時(shí)鐘周期。C++中就不是這么回事了;
一些老頑固的C程序員(比如我們中的一些曾)常常對(duì)這個(gè)特征很矛盾(你也可以說是敵對(duì))。但是當(dāng)他們完成了到OO思想的轉(zhuǎn)變,他們就能時(shí)常體會(huì)到盡管C++對(duì)程序員隱藏了一些機(jī)制,它也提供了一個(gè)抽象層和表達(dá)上的經(jīng)濟(jì)(economy of expression(譯注:從成本上),這降低了維護(hù)成本又不會(huì)降低運(yùn)行時(shí)性能。
C++并沒有試圖讓差的程序員能夠避免寫出差的程序;它允許明理(reasonable)的開發(fā)者寫出出眾的軟件。
 

 


Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=624241

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多