首页 > 代码库 > C++ Primer 学习笔记_108(大结局!!!)_特殊工具与技术 --固有的不可移植的特征[下]
C++ Primer 学习笔记_108(大结局!!!)_特殊工具与技术 --固有的不可移植的特征[下]
特殊工具与技术[大结局]
--固有的不可移植的特征[下]
三.链接指示:extern “C”
C++ 程序有时需要调用用其他程序设计语言编写的函数,最常见的一语言是C 语言。像任何名字一样,必须声明用其他语言编写的函数的名字,该声明必须指定返回类型和形参表。编译器按处理普通 C++ 函数一样的方式检查对外部语言函数的调用,但是,编译器一般必须产生不同的代码来调用用其他语言编写的函数。C++ 使用链接指示指出任意非 C++ 函数所用的语言。
1.声明非C++函数
链接指示不能出现在类定义或函数定义的内部,它必须出现在函数的第一次声明(谨记此处为声明)上。如:cstdlib中声明的一些C函数
//单个的 extern "C" size_t strlen(const char *); //复合的 extern "C" { int strcmp(const char *,const char *); char *strcat(char *,const char *); }
[说明]
1)extern后面接字符串字面值,字符串字面值指出编写函数所用的编程语言.
2)忽略了花括号,花括号中声明的函数名就是可见的,就像在花括号之外声明函数一样.
2.链接指示与头文件
可以将多重声明形式应用于整个头文件.例如,C++ 的 cstring 头文件可以像这样:
extern "C" { #include <string.h> }
当将 #include 指示在复合链接指示的花括号中的时候,假定头文件中的所有普通函数声明都是用链接指示的语言编写的函数。链接指示可以嵌套,所以,如果头文件包含了带链接指示的函数,该函数的链接不受影响。
允许将 C++ 从 C 函数库继承而来的函数定义为 C 函数,但不是必须定义为 C 函数--决定是用 C 还是用 C++ 实现 C 函数库,是每个 C++ 实现的事情。
3.导出C++函数到其他语言
通过对函数定义(谨记此处为定义)使用链接指示,使得用其他语言编写的程序可以使用C++函数:
extern "C" double calc(double dparm) { /**.....**/ }
当编译器为该函数产生代码的时候,它将产生适合于指定语言的代码。
用链接指示定义的函数的每个声明都必须使用相同的链接指示。
4.链接指示支持的语言
要求编译器支持对 C 语言的链接指示。编译器可以为其他语言提供链接说明。例如,extern "Ada"、extern "FORTRAN",extern “Java”(g++可以对Java进行支持) 等。
[注解]
支持什么语言随编译器而变。你必须查阅用户指南,获得关于编译器可以提供的任意非 C 链接说明的进一步信息。
对链接到 C 的预处理器支持有时需要在 C 和 C++ 中编译同一源文件。当编译 C++ 时,自动定义预处理器名字 __cplusplus(两个下划线),所以,可以根据是否正在编译 C++ 有条件地包含代码
#ifdef __cplusplus extern "C" #endif // __cplusplus int strcmp(const char *,const char *);
5.重载函数与链接指示
链接指示与函数重载之间的相互作用依赖于目标语言。如果语言支持重载函数,则为该语言实现链接指示的编译器很可能也支持 C++ 的这些函数的重载。
C++ 保证支持的唯一语言是 C。C 语言不支持函数重载,所以,在一组重载函数中只能为一个 C 函数指定链接指示。用带给定名字的 C 链接声明多于一个函数是错误的:
extern "C" void print(const char *); extern "C" void print(int); //Error
在 C++ 程序中,重载 C 函数很常见,但是,重载集合中的其他函数必须都是 C++ 函数:
class SmallInt { /*...*/ }; class BigNum { /*...*/ }; extern "C" double calc(double); SmallInt calc(SmallInt &); BigNum calc(BigNum &); //OK
可以从 C 程序和 C++ 程序调用 calc 的 C 版本。其余函数是带类型形参的 C++ 函数,只能从 C++ 程序调用。声明的次序不重要。
6.extern “C” 函数的指针
编写函数所用的语言是函数类型的一部分。为了声明用其他程序设计语言编写的函数的指针,必须使用链接指示:
extern "C" void (*pf)(int);
使用pf调用函数的时候,假定该调用是一个C函数调用而编译该函数.
C 函数的指针与 C++ 函数的指针具有不同的类型,不能将 C 函数的指针初始化或赋值为 C++ 函数的指针(反之亦然)。 存在这种不匹配的时候,会给出编译时错误:
void (*pfC)(int); extern void (*pfCPP)(int); pfC = pfCPP; //Error
7.应用于整个声明的链接指示
使用链接指示的时候,它应用于函数和任何函数指针,作为返回类型或形参类型使用:
extern "C" void f1(void (*)(int));
这个声明是说,f1 是一个不返回值的 C 函数,它有一个形参,该形参是不返回值并接受单个形参的函数的指针。链接指示应用于该函数指针以及 f1。调用的时候,必须将 C 函数名字或 C 函数指针传递给它。
因为链接指示应用于一个声明中的所有函数,所以必须使用类型别名,以便将 C 函数的指针传递给 C++ 函数:
extern "C" typedef void FC(int); void f2(FC *);