函數原型里的外部“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年的專業經驗。