欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
如何混合使用C和C(下)
Mixing C and C++ Code in the Same Program
ByStephen Clamage, Sun Microsystems, Sun ONE Studio Solaris Tools Development Engineering
Translator: Qiu Longbin <robin.qiu(at)yeah.net>
C++語(yǔ)言提供了一個(gè)混合代碼的機制,使得代碼可以在同一個(gè)程序中被兼容的C和C++編譯器編譯。在你移植代碼到不同的平臺和編譯器時(shí),你會(huì )體驗到不同的成功度。本文展示了當你混合使用C,C++時(shí),如何解決出現的一般的問(wèn)題。文中所有情況,展示了使用Sun C和C++編譯器時(shí)所要做的事情。(譯注:GCC的gcc和g++也是這一對組合。)
內容
-
使用兼容的編譯器
-
在C++源代碼中訪(fǎng)問(wèn)C代碼
-
在C源代碼中訪(fǎng)問(wèn)C++代碼
-
混合IOstream和C標準I/O
-
使用指向函數的指針
-
使用C++異常
-
鏈接程序
使用兼容的編譯器
混合代碼的第一個(gè)要求就是你使用的C和C++編譯器必須是兼容的。他們必須以同樣的方式,(例如),定義了基本類(lèi)型如int, float或指針。Solaris操作系統指定了C程序的應用程序的二進(jìn)制接口(ABI),它包含關(guān)于基本類(lèi)型和函數如何被調用的信息。任何Solaris Os上可用的編譯器都必須遵循ABI。
Sun C和C++編譯器遵循Solaris OS ABI并且是兼容的。第三方的Solaris OS C編譯器也必須遵循ABI。任何與Solaris Os兼容的C編譯器也同樣與Sun C++編譯器兼容。
被你的C編譯器使用的C運行時(shí)庫也必須同C++編譯器兼容。C++包括了標準C運行時(shí)庫作為其子集,只有稍許不同。如果C++編譯器提供了自己版本的C頭文件,那么這些頭文件的版本被C使用時(shí)也必須是兼容的。
Sun C和C++編譯器使用兼容的頭文件,并且使用同樣的C運行時(shí)庫。他們是完全兼容的。
在C++源代碼中訪(fǎng)問(wèn)C代碼
C++語(yǔ)言提供了一個(gè)“鏈接規范(linkage specification)”,用它你可以聲明函數或對象遵循特定語(yǔ)言的程序鏈接約定。對象和函數的默認鏈接是C++的。所有C++編譯器也為兼容的C編譯器提供了C鏈接。
當你需要訪(fǎng)問(wèn)一個(gè)用C鏈接編譯的函數(例如,某個(gè)函數被C編譯器編譯),就要聲明那個(gè)函數具備C鏈接(譯注:在C++代碼中)。即使大多數C++編譯器對C和C++數據對象的鏈接沒(méi)有什么不同,你也需要在你的C++代碼中聲明C數據對象(data objects)具有C鏈接。類(lèi)型(types)沒(méi)有C或C++鏈接,除了指向函數的指針(pointer-to-function)類(lèi)型。
聲明鏈接規范
使用下述標記之一來(lái)聲明一個(gè)對象或函數具備某種語(yǔ)言language_name的鏈接。
extern "language_name" declaration ; extern "language_name" { declaration ; declaration ; ... }
第一個(gè)標記指定了緊隨其后的聲明(或定義)具有語(yǔ)言language_name的鏈接約定。第二個(gè)標記指定花括號內的所有都具有language_name的鏈接。注意,第二個(gè)標記的最后花括號后面不要有分號。
你可以嵌套鏈接規范,他們沒(méi)有創(chuàng )建一個(gè)范圍域(scope)??紤]下面的例子:
extern "C" { void f(); // C linkage extern "C++" { void g(); // C++ linkage extern "C" void h(); // C linkage void g2(); // C++ linkage } extern "C++" void k();// C++ linkage void m(); // C linkage }
所有上面的函數都在相同的全局域,盡管是嵌套了鏈接規范。
在C++代碼中包含C頭文件
如果你想使用一個(gè)C庫,它定義的頭文件意欲為C編譯器所準備,你可以在extern “C”花括號中包含這個(gè)頭文件:
extern "C" { #include "header.h" }
Warning-警告-
不用為Solaris OS上的系統頭文件使用該技術(shù)。Solaris頭文件,并且所有賴(lài)于Sun C和C++編譯器的頭文件都已經(jīng)為C和C++編譯器做好了準備。如果你指定了一個(gè)鏈接,你可能使得聲明于Solaris頭文件中的聲明失效。
創(chuàng )建混合語(yǔ)言(Mixed-Languge)的頭文件
如果你想使得頭文件同時(shí)適合于C和C++編譯器,你可能把所有聲明都放置在了extern “C”花括號中,但是C編譯器并不認識這些語(yǔ)法。每個(gè)C++編譯器都預定義了宏__cplusplus,這樣你就可以使用這個(gè)宏來(lái)防衛C++語(yǔ)法擴展:
#ifdef __cplusplus extern "C" { #endif ... /* body of header */   #ifdef __cplusplus } /* closing brace for extern "C" */ #endif
給C structs增加C++特征
假定你想在你的C++代碼中更容易地使用C庫。并且假定你不使用C風(fēng)格的訪(fǎng)問(wèn)方式,你可能想增加成員函數,或許虛函數,也可能從class派生等等。你如何完成這個(gè)變換并確保C庫函數仍然能識別你的struct?考慮下面這個(gè)例子中C的struct buf的使用:
/* buf.h */ struct buf { char* data; unsigned count; }; void buf_clear(struct buf*); int buf_print(struct buf*); /* return status, 0 means fail */ int buf_append(struct buf*, const char*, unsigned count); /* same return */
你想把這個(gè)struct轉變進(jìn)C++ class,并做下述改變,使它更容易使用:
extern "C" { #include "buf.h" } class mybuf { // first attempt -- will it work? public: mybuf() : data(0), count(0) { } void clear() { buf_clear((buf*)this); } bool print() { return buf_print((buf*)this); } bool append(const char* p, unsigned c) { return buf_append((buf*)this, p, c); } private: char* data; unsigned count; };
class mybuf的接口看來(lái)更象C++代碼,并且更容易整合進(jìn)面向對象風(fēng)格的編程 ─ 如果它可行的話(huà)。
當成員函數傳遞this指針給buf函數時(shí)發(fā)生了什么?C++類(lèi)布局(layout)匹配C布局嗎?this指針指向數據成員,還是指向buf?如果增加虛函數到mybuf又會(huì )如何呢?
C++標準對buf和class mybuf的兼容性沒(méi)有任何保證。這里的代碼,沒(méi)有虛函數,可以工作,但你不能指望這個(gè)。如果你增加了虛函數,這個(gè)代碼會(huì )失敗,因為編譯器增加了額外的數據(比如指向虛表的指針)放在class的開(kāi)始處。
可移植的方案是把struct buf單獨放著(zhù)不動(dòng)它,盡管你想保護數據成員并僅僅通過(guò)成員函數提供訪(fǎng)問(wèn)。僅當你不改變聲明的情況下,你才能保證C和C++的兼容性。
你可以從C struct buf派生出一個(gè)C++ class mybuf,并且傳遞指向基類(lèi)buf的指針給mybuf的成員函數。當轉換mybuf* 到 buf*時(shí),如果指向mybuf的指針沒(méi)有指向buf數據的起始處,C++編譯器會(huì )自動(dòng)調整它。mybuf的布局在C++編譯時(shí)可能發(fā)生改變,但是操縱mybuf和buf對象的C++源代碼將到處都可以工作。下面的例子展示了一個(gè)可移植方法給C struct增加C++和面向對象特征:
extern "C" { #include "buf.h" } class mybuf : public buf { // a portable solution public: mybuf() : data(0), count(0) { } void clear() { buf_clear(this); } bool print() { return buf_print(this); } bool append(const char* p, unsigned c) { return buf_append(this, p, c); } };
C++代碼可以自由的創(chuàng )建和使用mybuf對象,傳遞它們到那些期望buf對象的C代碼,并且可以結合地很好。當然如果你為mybuf增加了數據成員,C代碼就不知道它們。那就是一般類(lèi)設計的考慮。你要當心要一致性地創(chuàng )建和刪除(delete)buf和mybuf對象.讓C代碼刪除(free)一個(gè)有C代碼創(chuàng )建的對象是最安全的,并且不允許C代碼刪除一個(gè)mybuf對象。
在C源代碼中訪(fǎng)問(wèn)C++代碼:
如果你聲明一個(gè)C++函數具有C鏈接,它就可以在由C編譯器編譯的函數中被調用。一個(gè)聲明具有C鏈接的函數可以使用所有C++的特征,如果你想在C代碼中訪(fǎng)問(wèn)它,它的參數和返回值必須是在C中可訪(fǎng)問(wèn)的。例如,如果一個(gè)函數聲明有一個(gè)IOstream類(lèi)的引用作為參數,就沒(méi)有(可移植的)方法來(lái)解析這個(gè)參數類(lèi)型給C編譯器。C語(yǔ)言沒(méi)有引用,模板,或具備C++特征的class.
這里是一個(gè)具備C鏈接的C++函數的例子:
#include <iostream> extern "C" int print(int i, double d) { std::cout << "i = " << i << ", d = " << d; }
你可以在頭文件中聲明一個(gè)函數print,被C和C++代碼共用:
#ifdef __cplusplus extern "C" #endif int print(int i, double d);
你可以至多聲明重載集中的一個(gè)函數作為extern “C”,因為一個(gè)C函數僅僅可以有一個(gè)給定的名字。如果你要在C中訪(fǎng)問(wèn)重載函數,你可以以不同的名字寫(xiě)出C++ wrapper函數,見(jiàn)下面的例子:
int g(int); double g(double); extern "C" int g_int(int i){ return g(i); } extern "C" double g_double(double d) { return g(d); }
這里是C頭文件wrapper函數的例子:
int g_int(int); double g_double(double);
你也需要包裹(wrapper)函數來(lái)調用template functions,因為template functions不能聲明為extern “C”:
template<class T> T foo(T t) { ... }   extern "C" int foo_of_int(int t) { return foo(t); } extern "C" char* foo_of_charp(char* p) { return foo(p); }
C++代碼仍然可以訪(fǎng)問(wèn)重載函數和template functions。C代碼必須使用wrapper functions。
在C中訪(fǎng)問(wèn)C++ class
能夠從C代碼中訪(fǎng)問(wèn)C++ class嗎?你可以聲明一個(gè)C struct,看上去象一個(gè)C++ class并能以某種方式調用成員函數嗎?答案是肯定的,雖然你必須為維持可移植性增加一些復雜性。任何對C++ class的定義的修改都要求你重新審查你的C代碼。
假定你有一個(gè)C++ class如下:
class M { public: virtual int foo(int); // ... private: int i, j; };
你不能在C代碼中聲明class M。你能做的最好的事就是傳遞指向class M 對象的指針,這類(lèi)似于在C標準I/O中傳遞FILE對象。你可以在C++中寫(xiě)extern “C”函數訪(fǎng)問(wèn)class M 對象并在C代碼中調用這些函數。下面是一個(gè)C++函數,被設計來(lái)調用成員函數foo:
extern "C" int call_M_foo(M* m, int i) { return m->foo(i); }
下面是C代碼的一個(gè)例子,它使用了class M:
struct M; /* you can supply only an incomplete declaration */ int call_M_foo(struct M*, int); /* declare the wrapper function */ int f(struct M* p, int j) /* now you can call M::foo */ { return call_M_foo(p, j); }
混合IOstream和C標準I/O
你可以在C++程序中使用來(lái)自于標準C頭文件<stdio.h>的C標準I/O,因為C標準I/O是C++的一部分。
任何關(guān)于在同一個(gè)程序中混合IOstream和標準I/O的考慮都不依賴(lài)于程序是否以明確地包含C代碼。這個(gè)問(wèn)題對于純粹的C++程序使用標準I/O和IOstream是一樣的。
Sun C和C++使用同樣的C運行時(shí)庫,這在關(guān)于兼容的編譯器小節中注明過(guò)了。使用Sun編譯器,你可以在同一個(gè)程序中自由地在C和C++代碼中使用標準I/O。
C++標準說(shuō),你可以在同一個(gè)目標“流(stream)”上混合使用標準I/O函數和IOstream函數,比如標準輸入和輸出流。但是C++實(shí)現在它們的遵從度上可能不同。一些系統要求你在做任何I/O之前先顯式地調用sync_with_stdio()函數。在同一個(gè)流或者文件上混合I/O風(fēng)格,實(shí)現品在I/O的效能方面也不同。最差情況下,你得到為每個(gè)字符的輸入輸出做一個(gè)系統調用的結果。如果程序有大量的I/O,性能可能是不可接受的。
最安全的途徑是對任一給定的文件/標準流,堅持使用標準I/O或IOstream風(fēng)格。在一個(gè)文件或流上使用標準I/O,在另一個(gè)不同的一個(gè)文件或流上使用IOstream,不會(huì )導致任何問(wèn)題。
使用指向函數的指針
指向函數的指針必須指明是否指向一個(gè)C函數或C++函數,因為C和C++函數可能采用不同的調用約定。否則,編譯器不知道究竟要產(chǎn)生哪種函數調用的代碼。多數系統對C和C++并沒(méi)有不同的調用約定,但是C++允許存在這種可能性。因此你必須在聲明指向函數的指針時(shí)要小心,確保類(lèi)型匹配??紤]下面的例子:
typedef int (*pfun)(int); // line 1 extern "C" void foo(pfun); // line 2 extern "C" int g(int) // line 3 ... foo( g ); // Error! // line 5
Line 1聲明了pfun指向一個(gè)C++函數,因為它缺少鏈接說(shuō)明符。
Line 2聲明foo為一個(gè)C函數,它具有一個(gè)指向C++函數的指針。
Line 5試圖用指向g的指針調用foo,g是一個(gè)C函數,所以類(lèi)型不匹配。
要確保指向函數的指針的鏈接規范與它將要指向的函數匹配。在下面這個(gè)正確的例子中,所有聲明都包含在extern “C”花括號中,確保了類(lèi)型匹配。
extern "C" { typedef int (*pfun)(int); void foo(pfun); int g(int); } foo( g ); // now OK
指向函數指針有另外一個(gè)微妙之處,它可能給程序員帶來(lái)陷阱。鏈接規范應用于函數所有的參數類(lèi)型和返回類(lèi)型上。如果你將一個(gè)詳細聲明的指向函數的指針(pointer-to-function)用作函數參數,鏈接規范也同樣地作用在了這個(gè)指向函數的指針上。如果你通過(guò)使用typedef聲明了一個(gè)指向函數的指針,這個(gè)typedef類(lèi)型在用于函數聲明中時(shí),鏈接規范不會(huì )受到影響。例如,考慮下面的代碼:
typedef int (*pfn)(int); extern "C" void foo(pfn p) { ... } // definition extern "C" void foo( int (*)(int) ); // declaration
前兩行可以出現在一個(gè)程序文件中,第三行可以出現在一個(gè)頭文件中,在此頭文件中你不想暴露出內部使用的typedef的名字。盡管你想讓foo的聲明和定義相匹配,但它們不匹配。foo的定義接受一個(gè)指向C++函數的指針,但是其聲明接受一個(gè)指向C函數的指針。這段代碼聲明了一對重載函數。(譯注:在此是參數類(lèi)型的鏈接規范不同。)
為了避免這個(gè)問(wèn)題,得在聲明中一致地使用typedefs,或者以某個(gè)適當的鏈接規范包圍typedefs。例如,假定你想讓foo接受一個(gè)指向C函數的指針,你可以以下面的方式寫(xiě)出foo的定義:
extern "C" { typedef int (*pfn)(int); void foo(pfn p) { ... } }
使用C++異常
傳播(Propagating)異常
從C函數中調用C++函數,并且C++函數拋出了一個(gè)異常,將會(huì )發(fā)生什么?在是否會(huì )使得該異常有適當的行為這個(gè)問(wèn)題上C++標準有些含糊,并且在一些系統上你不得不采取特別的預防措施。一般而言,你必須得求諸用戶(hù)手冊來(lái)確定代碼是否以適當的方式工作。
Sun C++中不需要預防措施。Sun C++中的異常機制不影響函數調用的方式。當C++異常被拋出時(shí),如果一個(gè)C函數正處于活動(dòng)狀態(tài),C函數將轉交給異常處理過(guò)程。
混合異常和set_jmp,long_jmp
最好的建議是在包含C++代碼的程序中不要使用long_jmp。C++異常機制和C++關(guān)于銷(xiāo)毀超出作用域對象的規則可能被long_jmp違反,從而得到不確定的結果。一些編譯器整合了異常和long_jmp,允許它們協(xié)同工作,但你不能依賴(lài)這樣的行為。Sun C++使用與C編譯器相同的set_jmp和long_jmp。
許多C++專(zhuān)家相信long_jmp不應該與異常整合,因為很困難準確地指定它該如何作為。
如果你在混合有C++的C代碼中使用long_jmp,要確保long_jmp不要跨越(cross over)活動(dòng)的C++函數。如果你不能確保這點(diǎn),查看一下是否你可以通過(guò)禁用異常來(lái)編譯那個(gè)C++代碼。如果對象的析構器被繞過(guò)了,你仍舊可能有問(wèn)題。
鏈接程序
某時(shí),多數C++編譯器要求main函數要被C++編譯。這個(gè)要求今天來(lái)說(shuō)并不常見(jiàn),Sun C++就不要求這點(diǎn)。如果你的C++編譯器需要編譯main函數,但你由于某種原因不能這么做,你可以改變C main函數的名字并從一個(gè)C++ main的包裹函數中調用它。例如,改變C main函數的名字為C_main,并寫(xiě)如下C++代碼:
extern "C" int C_main(int, char**); // not needed for Sun C++ int main(int argc, char** argv) { return C_main(argc, argv); }
當然,C_main必須是被聲明在C代碼中,并返回一個(gè)int。如上注解,使用Sun C++是不會(huì )有這個(gè)麻煩。
即使你的程序主要由C代碼構成,但使用了C++庫,你需要鏈接C++運行時(shí)以支持與C++編譯器提供的庫一起編譯進(jìn)程序。做這件事的最簡(jiǎn)單和最好的方式是使用C++編譯器驅動(dòng)鏈接過(guò)程。C++編譯器的驅動(dòng)器知道要鏈接什么庫,次序如何。特定的庫可以依賴(lài)編譯C++代碼時(shí)使用的選項。
假定你有C程序文件main.o, f1.o和f2.o,你可以使用C++程序庫helper.a。用Sun C++,你要如下引發(fā)命令行:
CC -o myprog main.o f1.o f2.o helper.a
必要的C++運行時(shí)庫,如libCrun和libCstd被自動(dòng)地鏈接進(jìn)去。helper.a可能要求使用額外的鏈接選項。如果你由于某種原因不能使用C++編譯器,你可以使用CC命令的dryrun選項來(lái)獲得編譯器引發(fā)出的命令列表,并把它們捕獲進(jìn)一個(gè)shell腳本。因為確切的命令(復數)依賴(lài)于命令行選項,你應該復查—dryrun選項輸出和命令行的任何一個(gè)變動(dòng)。
更多信息
-
Sun ONE Studio C/C++ Documentation
Sun ONE C和C++編譯器的最新信息,包括man手冊頁(yè)和readme文件。
關(guān)于作者
Steve Clamage從1994年在Sun至今?。它當前是C++編譯器和Sun ONE Studio編譯器套件的技術(shù)領(lǐng)導。它從1995年開(kāi)始是ANSI C++委員會(huì )的主席。
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=626342
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
同一程序中混合調用C和C++代碼
ffmpeg鏈接錯誤:關(guān)于C++ extern "C"
新版 C# 高效率編程指南
編寫(xiě)跨平臺的軟件入門(mén)
C標準庫函數淺析
unix消息隊列學(xué)習筆記
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久