C++中extern C的使用
C++程序有時需要調(diào)用其它語言編寫的函數(shù),最常見的是調(diào)用C語言編寫的函數(shù)。像所有其它名字一樣,其它語言中的函數(shù)名字也必須在C++中進(jìn)行聲明,并且該聲明必須指定返回類型和形參列表。對于其它語言編寫的函數(shù)來說,編譯器檢查其調(diào)用的方式與處理普通C++函數(shù)的方式相同,但是生成的代碼有所區(qū)別。C++使用鏈接指示(linkage? directive)指出任意非C++函數(shù)所用的語言。
鏈接指示(linkage directive):支持C++程序調(diào)用其它語言編寫的函數(shù)的一種機(jī)制。所有編譯器都應(yīng)支持調(diào)用C++和C函數(shù),至于是否支持其它語言則由編譯器決定。
要想把C++代碼和其它語言(包括C語言)編寫的代碼放在一起使用,要求我們必須有權(quán)訪問該語言的編譯器,并且這個編譯器與當(dāng)前的C++編譯器是兼容的。
聲明一個非C++的函數(shù):鏈接指示可以有兩種形式:單個的或復(fù)合的。鏈接指示不能出現(xiàn)在類定義或函數(shù)定義的內(nèi)部。同樣的鏈接指示必須在函數(shù)的每個聲明中都出現(xiàn)。
鏈接指示的第一種形式包含一個關(guān)鍵字extern,后面是一個字符串字面值常量以及一個”普通的”函數(shù)聲明。其中的字符串字面值常量指出了編寫函數(shù)所用的語言。編譯器應(yīng)該支持對C語言的鏈接指示。此外,編譯器也可能會支持其它語言的鏈接指示,如extern “Ada”、extern “FORTRAN”等。
鏈接指示與頭文件:我們可以令鏈接指示后面跟上花括號括起來的若干函數(shù)的聲明,從而一次性建立多個鏈接。花括號的作用是將適用于該鏈接指示的多個聲明聚合在一起,否則花括號就會被忽略,花括號中聲明的函數(shù)名字就是可見的,就好像在花括號之外聲明的一樣。多重聲明的形式可以應(yīng)用于整個頭文件。
當(dāng)一個#include指示被放置在復(fù)合鏈接指示的花括號中時,頭文件中的所有普通函數(shù)聲明都被認(rèn)為是由鏈接指示的語言編寫的。鏈接指示可以嵌套,因此如果頭文件包含帶自帶鏈接指示的函數(shù),則該函數(shù)的鏈接不受影響。
C++從C語言繼承的標(biāo)準(zhǔn)庫函數(shù)可以定義成C函數(shù),但并非必須:決定使用C還是C++實(shí)現(xiàn)C標(biāo)準(zhǔn)庫,是每個C++實(shí)現(xiàn)的事情。
指向extern “C”函數(shù)的指針:編寫函數(shù)所用的語言是函數(shù)類型的一部分。因此,對于使用鏈接指示定義的函數(shù)來說,它的每個聲明都必須使用相同的鏈接指示。而且,指向其它語言編寫的函數(shù)的指針必須與函數(shù)本身使用相同的鏈接指示。指向C函數(shù)的指針與指向C++函數(shù)的指針是不一樣的類型。一個指向C函數(shù)的指針不能用在指向初始化或賦值操作后指向C++函數(shù),反之亦然。就像其它類型不匹配的問題一樣,如果我們試圖在兩個鏈接指示不同的指針之間進(jìn)行賦值操作,則程序?qū)l(fā)生錯誤。
鏈接指示對整個聲明都有效:當(dāng)我們使用鏈接指示時,它不僅對函數(shù)有效,而且對作為返回類型或形參類型的函數(shù)指針也有效。因?yàn)殒溄又甘就瑫r作用于聲明語句中的所有函數(shù),所以如果我們希望給C++函數(shù)傳入一個指向C函數(shù)的指針,則必須使用類型別名。
導(dǎo)出C++函數(shù)到其它語言:通過使用鏈接指示對函數(shù)進(jìn)行定義,我們可以令一個C++函數(shù)在其它語言編寫的程序中可用。值得注意的是,可被多種語言共享的函數(shù)的返回類型或形參類型受到很多限制。例如,我們不太可能把一個C++類的對象傳給C程序,因?yàn)镃程序根本無法理解構(gòu)造函數(shù)、析構(gòu)函數(shù)以及其它類特有的操作。
對鏈接到C的預(yù)處理器的支持:有時需要在C和C++中編譯同一個源文件,為了實(shí)現(xiàn)這一目的,在編譯C++版本的程序時預(yù)處理器定義__cplusplus(兩個下劃線)。利用這個變量,我們可以在編譯C++程序的時候有條件地包含進(jìn)來一些代碼。
重載函數(shù)與鏈接指示:鏈接指示與重載函數(shù)的相互作用依賴于目標(biāo)語言。如果目標(biāo)語言支持重載函數(shù),則為該語言實(shí)現(xiàn)鏈接指示的編譯器很可能也支持重載這些C++的函數(shù)。C語言不支持函數(shù)重載,因此也就不難理解為什么一個C鏈接指示只能用于說明一組重載函數(shù)中的某一個了。如果在一組重載函數(shù)中有一個是C函數(shù),則其余的必定都是C++函數(shù)。
C++雖然兼容C,但C++文件中函數(shù)編譯后生成的符號與C語言生成的不同。相同的函數(shù),在C和C++中,編譯后生成的符號不同。
extern"C"的主要作用就是為了能夠正確實(shí)現(xiàn)C++代碼調(diào)用其它C語言代碼。加上extern "C"后,會指示編譯器這部分代碼按C語言的進(jìn)行編譯,而不是C++的。由于C++支持函數(shù)重載,因此編譯器編譯函數(shù)的過程中會將函數(shù)的參數(shù)類型也加到編譯后的代碼中,而不僅僅是函數(shù)名;而C語言并不支持函數(shù)重載,因此編譯C語言代碼的函數(shù)時不會帶上函數(shù)的參數(shù)類型,一般只包括函數(shù)名。
extern "C" makes a function-name in C++ have 'C' linkage (compiler does not mangle the name) so that client C code can link to (i.e use) your function using a 'C' compatible header file that contains just the declaration of your function. Your function definition is contained in a binary format (that was compiled by your C++ compiler) that the client 'C' linker will then link to using the 'C' name.
Since C++ has overloading of function names and C does not, the C++ compiler cannot just use the function name as a unique id to link to, so it mangles the name by adding information about the arguments. A C compiler does not need to mangle the name since you can not overload function names in C. When you state that a function has extern "C" linkage in C++, the C++ compiler does not add argument/parameter type information to the name used for linkage.
Just so you know, you can specify "C" linkage to each individual declaration/definition explicitly or use a block to group a sequence of declarations/definitions to have a certain linkage. (from:? https://stackoverflow.com/questions/1041866/in-c-source-what-is-the-effect-of-extern-c?)?
下面是從其他文章中copy的測試代碼,詳細(xì)內(nèi)容介紹可以參考對應(yīng)的reference:
c_head.h:
#ifndef FBC_CPPBASE_C_HEAD_H_
#define FBC_CPPBASE_C_HEAD_H_void tmp_f(void);#endif // FBC_CPPBASE_C_HEAD_H_
c_head.c:
#include "c_head.h"
#include <stdio.h>void tmp_f(void)
{fprintf(stdout, "\n This is a C code\n");
}
extern_c.hpp:
#ifndef FBC_CPPBASE_EXTERN_C_HPP_
#define FBC_CPPBASE_EXTERN_C_HPP_namespace extern_c_ {// the first method
#ifdef __cplusplus
extern "C" {
#include "c_head.h"
}
#endif// the second method
//extern "C" void tmp_f(void);int test_extern_c_1();} // namespace extern_c_#endif // FBC_CPPBASE_EXTERN_C_HPP_
extern_c.cpp:
#include "extern_c.hpp"
#include <iostream>namespace extern_c_ {
//
// reference: http://www.thegeekstuff.com/2013/01/mix-c-and-cpp/
int test_extern_c_1()
{tmp_f();return 0;
}///
// reference: https://stackoverflow.com/questions/1292138/when-to-use-extern-c-in-c
/*extern "C" makes names not mangled.It used when:1. We need to use some C library in C++extern "C" int foo(int);2. We need export some C++ code to Cextern "C" int foo(int) { something; }3. We need an ability to resolve symbol in shared library -- so we need to get rid manglingextern "C" int foo(int) { something; }typedef int (*foo_type)(int);foo_type f = (foo_type)dlsym(handle,"foo")
*/} // namespace extern_c_
GitHub: https://github.com/fengbingchun/Messy_Test
總結(jié)
以上是生活随笔為你收集整理的C++中extern C的使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Ubuntu 14.04 64位机上配置
- 下一篇: C++11中std::unique_lo