extern "C"
多用在用非C的语言写的程序意欲调用用C写成的库。用c写成的库里的函数名(肯定是由C编译器编译的)都是C的风格——也就是简单的一个函数名。比如函数void st_read(ft_t f)在库里的符号名就是st_read。
那么在你的程序中(假设是C++写成的)需要用到这个st_read函数,当然首先要声明这个函数,让编译器知道存在st_read这个符号名。这时,在声明这个函数时,就需要用extern "C",即:
extern "C" void st_read(ft_t f)
或者
extern "C"
{
void st_read(ft_t f)
}
如果不这样做在编译时,C++编译器就会把这个函数名编译成void_st_read_ft_txxx这样一个乱七八糟的形式(实际情况有出入),这主要 是C++为了重载而对同名函数做的区分。用这个乱七八糟的名字当然无法引用C库中的对应函数(上面已说了C库中的该函数符号名为简单的st_read)。
另外一个相反的情况就是你用其他非C语言写成了库,你想要C程序能够调用你的库中的函数,那么需要将那些需要导出的函数的声明用extern "C"修饰。这需要非C编译器支持extern "C"修饰。
如果不这样做在编译时,C++编译器就会把这个函数名编译成void_st_read_ft_txxx这样一个乱七八糟的形式(实际情况有出入),这主要 是C++为了重载而对同名函数做的区分。用这个乱七八糟的名字当然无法引用C库中的对应函数(上面已说了C库中的该函数符号名为简单的st_read)。
林锐的高质量C/C++编程有讲道,一下是我摘录的:
如果同名函数仅仅是返回值类型不同,有时可以区分,有时却不能.例如:
void Function(void);
int Function (void);
上述两个函数,第一个没有返回值,第二个的返回值是int类型.如果这样调用函数:
int x = Function ();
则可以判断出Function是第二个函数.问题是在C++/C程序中,我们可以忽略函数的
返回值.在这种情况下,编译器和程序员都不知道哪个Function函数被调用.
所以只能靠参数而不能靠返回值类型的不同来区分重载函数.编译器根据参数为每
个重载函数产生不同的内部标识符.例如编译器为示例8-1-1中的三个Eat函数产生象
_eat_beef,_eat_fish,_eat_chicken之类的内部标识符(不同的编译器可能产生不同
风格的内部标识符).
如果C++程序要调用已经被编译后的C函数,该怎么办
假设某个C函数的声明如下:
void foo(int x, int y);
该函数被C编译器编译后在库中的名字为_foo,而C++编译器则会产生像_foo_int_int
之类的名字用来支持函数重载和类型安全连接.由于编译后的名字不同,C++程序不能
直接调用C函数.C++提供了一个C连接交换指定符号extern"C"来解决这个问题.
例如:
extern "C"
{
void foo(int x, int y);
… // 其它函数
}
或者写成
extern "C"
{
#include "myheader.h"
… // 其它C头文件
}
这就告诉C++编译译器,函数foo是个C连接,应该到库中找名字_foo而不是找
_foo_int_int.C++编译器开发商已经对C标准库的头文件作了extern"C"处理,所以
我们可以用#include 直接引用这些头文件.
注意并不是两个函数的名字相同就能构成重载.全局函数和类的成员函数同名不算
重载,因为函数的作用域不同.例如:
void Print(…); // 全局函数
class A
{…
void Print(…); // 成员函数
高质量C++/C 编程指南,v 1.0
2001 Page 59 of 101
}
不论两个Print函数的参数是否不同,如果类的某个成员函数要调用全局函数
Print,为了与成员函数Print区别,全局函数被调用时应加'::'标志.如
::Print(…); // 表示Print是全局函数而非成员函数
多用在用非C的语言写的程序意欲调用用C写成的库。用c写成的库里的函数名(肯定是由C编译器编译的)都是C的风格——也就是简单的一个函数名。比如函数void st_read(ft_t f)在库里的符号名就是st_read。
那么在你的程序中(假设是C++写成的)需要用到这个st_read函数,当然首先要声明这个函数,让编译器知道存在st_read这个符号名。这时,在声明这个函数时,就需要用extern "C",即:
extern "C" void st_read(ft_t f)
或者
extern "C"
{
void st_read(ft_t f)
}
如果不这样做在编译时,C++编译器就会把这个函数名编译成void_st_read_ft_txxx这样一个乱七八糟的形式(实际情况有出入),这主要 是C++为了重载而对同名函数做的区分。用这个乱七八糟的名字当然无法引用C库中的对应函数(上面已说了C库中的该函数符号名为简单的st_read)。
另外一个相反的情况就是你用其他非C语言写成了库,你想要C程序能够调用你的库中的函数,那么需要将那些需要导出的函数的声明用extern "C"修饰。这需要非C编译器支持extern "C"修饰。
如果不这样做在编译时,C++编译器就会把这个函数名编译成void_st_read_ft_txxx这样一个乱七八糟的形式(实际情况有出入),这主要 是C++为了重载而对同名函数做的区分。用这个乱七八糟的名字当然无法引用C库中的对应函数(上面已说了C库中的该函数符号名为简单的st_read)。
林锐的高质量C/C++编程有讲道,一下是我摘录的:
如果同名函数仅仅是返回值类型不同,有时可以区分,有时却不能.例如:
void Function(void);
int Function (void);
上述两个函数,第一个没有返回值,第二个的返回值是int类型.如果这样调用函数:
int x = Function ();
则可以判断出Function是第二个函数.问题是在C++/C程序中,我们可以忽略函数的
返回值.在这种情况下,编译器和程序员都不知道哪个Function函数被调用.
所以只能靠参数而不能靠返回值类型的不同来区分重载函数.编译器根据参数为每
个重载函数产生不同的内部标识符.例如编译器为示例8-1-1中的三个Eat函数产生象
_eat_beef,_eat_fish,_eat_chicken之类的内部标识符(不同的编译器可能产生不同
风格的内部标识符).
如果C++程序要调用已经被编译后的C函数,该怎么办
假设某个C函数的声明如下:
void foo(int x, int y);
该函数被C编译器编译后在库中的名字为_foo,而C++编译器则会产生像_foo_int_int
之类的名字用来支持函数重载和类型安全连接.由于编译后的名字不同,C++程序不能
直接调用C函数.C++提供了一个C连接交换指定符号extern"C"来解决这个问题.
例如:
extern "C"
{
void foo(int x, int y);
… // 其它函数
}
或者写成
extern "C"
{
#include "myheader.h"
… // 其它C头文件
}
这就告诉C++编译译器,函数foo是个C连接,应该到库中找名字_foo而不是找
_foo_int_int.C++编译器开发商已经对C标准库的头文件作了extern"C"处理,所以
我们可以用#include 直接引用这些头文件.
注意并不是两个函数的名字相同就能构成重载.全局函数和类的成员函数同名不算
重载,因为函数的作用域不同.例如:
void Print(…); // 全局函数
class A
{…
void Print(…); // 成员函数
高质量C++/C 编程指南,v 1.0
2001 Page 59 of 101
}
不论两个Print函数的参数是否不同,如果类的某个成员函数要调用全局函数
Print,为了与成员函数Print区别,全局函数被调用时应加'::'标志.如
::Print(…); // 表示Print是全局函数而非成员函数