分类: C/C++
2014-06-23 11:07:54
先对C中调用C++代码作个简单回顾:
1、 对于C++中非类的成员函数,可以简单的在函数声明前面加extern “C”,通常函数声明位于头文件中,当然也可以将声明和函数定义一起放在cpp中,在没有声明的情况下,直接在定义前添加extern “C”也可.
在 C 中调用 C++
Example 4.12 和Example 4.13 演示如何在 C 中调用 C++。
Example 4.12. 定义被调用的 C++ 函数
struct S { // has no base classes or virtual functions S(int s) : i(s) { } int i; }; extern "C" void cppfunc(S *p) { // Definition of the C++ function to be called from C. // The function is written in C++, only the linkage is C. p->i += 5; }
Example 4.13. 在 C 中声明并调用函数
struct S { int i; }; extern void cppfunc(struct S *p); /* Declaration of the C++ function to be called from C */ int f(void) { struct S s; s.i = 2; /* initialize 's' */ cppfunc(&s); /* call 'cppfunc' so it */ /* can change 's' */ return s.i * 3; }
2、 对于C++类的成员函数,则需要另外做一个cpp文件,将需要调用的函数进行包装。
以上两项的实例参看前面C中如何调用C++代码的文章。
要实现C++中调用C的代码,具体操作:
对于C中的函数代码,要么将C代码的头文件进行修改,在其被含入C++代码时在声明中加入extern “C”或者在C++代码中重新声明一下C函数,重新声明时添加上extern “C”头。
通过以上的说明,我明白一点,那就是加extern “C”头一定是加在C++的代码文件中才能起作用的。
下面分析一下这个现象的实质原因:
C编译器编译函数时不带函数的类型信息,只包含函数符号名字,如C编译器把函数int a(float x)编译成类似_a这样的符号,C连接器只要找到了调用函数的符号,就可以连接成功,它假设参数类型信息是正确的,这是C编译连接器的缺点。而C++编译器为了实现函数重载,编译时会带上函数的类型信息,如他把上面的a函数可能编译成_a_float这样的符号为了实现重载,注意它还是没有带返回值得信息,这也是为什么C++不支持采用函数返回值来区别函数重载的原因之一,当然,函数的使用者对函数返回值的处理方式(如忽略)也是重要原因。
基于以上,C调用C++,首先需要用封装函数把对C++的类等的调用封装成C函数以便C调用,于是extern "C"的作用是:让编译器知道这件事,然后以C语言的方式编译和连接封装函数(通常是把封装函数用C++编译器按C++方式编译,用了extern "C" 后,编译器便依C的方式编译封装接口,当然接口函数里面的C++语法还是按C++方式编译;对于C语言部分--调用者,还是按C语言编译;分别对C++接口部分和C部分编译后,再连接就可以实现C调用C++了)。相反,C++调用C函数,extern "C" 的作用是:让C++连接器找调用函数的符号时采用C的方式,即使用_a而不是_a_float来找调用函数。
将 C++ 函数声明为``extern "C"''(在你的 C++ 代码里做这个声明),然后调用它(在你的 C 或者 C++ 代码里调用)。例如:
// C++ code:
extern "C" void f(int);
void f(int i)
{
// ...
}
然后,你可以这样使用 f():
/* C code: */
void f(int);
void cc(int i)
{
f(i);
/* ... */
}
当然,这招只适用于非成员函数。如果你想要在 C 里调用成员函数(包括虚函数),则需要提供一个简单的包装(wrapper)。例如:
// C++ code:
class C
{
// ...
virtual double f(int);
};
extern "C" double call_C_f(C* p, int i) // wrapper function
{
return p->f(i);
}
然后,你就可以这样调用 C::f():
/* C code: */
double call_C_f(struct C* p, int i);
void ccc(struct C* p, int i)
{
double d = call_C_f(p,i);
/* ... */
}
如果你想在 C 里调用重载函数,则必须提供不同名字的包装,这样才能被 C 代码调用。例如:
// C++ code:
void f(int);
void f(double);
extern "C" void f_i(int i) { f(i); }
extern "C" void f_d(double d) { f(d); }
然后,你可以这样使用每个重载的 f():
/* C code: */
void f_i(int);
void f_d(double);
void cccc(int i,double d)
{
f_i(i);
f_d(d);
/* ... */
}
注意,这些技巧也适用于在 C 里调用 C++ 类库,即使你不能(或者不想)修改 C++ 头文件。
Example 4.8 和Example 4.9 演示如何在 C++ 中调用 C。
Example 4.8. 在 C++ 中调用 C 函数
struct S { // has no base classes
// or virtual functions
S(int s) : i(s) { }
int i;
}; extern "C" void cfunc(S *); // declare the C function to be called from C++
int f(){
S s(2); // initialize 's'
cfunc(&s); // call 'cfunc' so it can change 's'
return s.i * 3;
}
Example 4.9. 定义 C 函数
struct S { int i; }; void cfunc(struct S *p) { /* the definition of the C function to be called from C++ */ p->i += 5;
http://blog.csdn.net/liuchao1986105/article/details/6562037