函数原型里的外部“C”声明强制要求用于该函数的C连接(C linkage),而不是缺省的C++连接(C++ linkage)。这就意味着C连接会保证可以从使用其它编程语言写成的模块里调用一个函数——例如C、Fortran和COBOL——因为函数名是以一种大多数非C++的编译器和连接器都很熟悉的方式修饰的。
一个有趣的问题是,将静态成员函数的声明作为外部“C”是否被允许。例如:
struct C
{
extern "C" static void f(int); //
valid?
};
答案是不行。C++的标准是不允许成员函数,不论是静态的还是非静态的,被作为外部“C”声明。第一眼看上去,这个决定似乎过于严厉,因为你会把指向静态成员函数的指针作为普通函数的指针来对待,如下面的例子所示:
void (*pf) (int) = &C::f; // OK
名称修饰
你不能将静态成员函数作为外部“C”来声明有一个很合理的理由:名称修饰(也叫做name mangling)。C++的名称修饰是编译器将函数的名称转变成为一个唯一的字符串的过程,这个字符串会对函数的类、其命名空间、其参数表,以及其他等等进行编码。C++的命名修饰适用于静态成员函数,也适用于非静态成员函数。静态函数的命名修饰的一个好处之一,是能够在不同的类里使用同一个名称来声明两个或者更多的静态成员函数——而不会发生名称上的冲突。考虑一下下面的情况:
struct C
{
static void f(int);
};
struct D
{
static void f(int); // doesn't clash with
C::f
};
f()的外部“C”声明会禁止命名修饰;如果它被允许的话,那么不同类里具有相同名称的静态成员函数就会相互冲突。它的不足之处是,你不能从使用其它语言写成的模块里调用这些函数,因为它们有C++连接。
本文作者Danny Kalev 是一个系统分析家、软件工程师,在C++和面向对象设计方面有着14年的专业经验。