extern "C"
объявляет что-то, имеющее связь с языком C . Это отличается от внешней связи и внутренней связи . По умолчанию все в программе на C ++ имеет связь на языке C ++, хотя вы можете повторить это, указав extern "C++"
.
external linkage означает, что имя является видимым для других исходных файлов, скомпилированных отдельно, при условии, что вы включили правильные заголовки или предоставили правильные объявления. Это то, что позволяет вам определять функцию foo
в a.cpp
и вызывать ее из b.cpp
. Большинство имен в области имен в программе на C ++ имеют внешнюю связь. Исключения составляют те, которые имеют внутреннюю связь , и те, которые имеют отсутствие связи . Вы можете явно пометить что-то как имеющее внешнюю связь, указав extern
. Это отличается от extern "C"
.
внутренняя связь означает, что имя является уникальным для текущей единицы компиляции, и вы не можете получить доступ к переменной или функции из другого исходного файла. Переменные области видимости файлов и функции, объявленные static
, имеют внутреннюю связь. Кроме того, const
целочисленные переменные в области имен, которые инициализируются константным выражением, по умолчанию имеют внутреннюю связь, хотя вы можете переопределить ее явным extern
.
Наконец, локальные переменные и классы имеют без связи . Имена являются локальными для функции, в которой они объявлены, и не могут быть доступны извне этой функции. Вы можете использовать extern
, чтобы указать, что вы действительно хотите получить доступ к переменной в области имен.
Шаблоны не могут быть определены в локальной области, но могут иметь внутреннюю или внешнюю связь.
int i; // namespace scope variable has external linkage
extern int j; // explicitly mark j with external linkage
static int k; // k has internal linkage
int const n=42; // internal linkage
extern int const m=99; // external linkage
void foo(); // foo has external linkage; it may be defined in this source file or another
extern void foo(); // explicitly mark foo with external linkage
static void bar(); // bar has internal linkage, and must be defined in this source file
void foo(){} // definition of foo, visible from other source files
void bar(){} // definition of bar, not visible from other source files (internal linkage)
static void baz(){} // declare and define baz with internal linkage
template<typename T> void foobar(){} // foobar has external linkage
template<typename T>
static void foobaz(){} // foobaz has internal linkage
void wibble()
{
int i; // local, no linkage
extern int i; // references i, declared above with external linkage
}
extern "C"
{
int i2; // namespace scope variable has external linkage, and "C" linkage
extern int j2; // explicitly mark j2 with external linkage and "C" linkage
static int k2; // k2 has internal linkage and "C" linkage
int const n2=42; // internal linkage and "C" linkage
extern int const m2=99; // external linkage and "C" linkage
void foo2(); // foo2 has external linkage and "C" linkage
static void bar2(); // bar2 has internal linkage and "C" linkage
void foo2(){} // definition of foo2, still with external linkage and "C" linkage
void bar2(){} // definition of bar2, still with internal linkage and "C" linkage
static void baz(){} // declare and define baz with internal linkage
}
Сообщение об ошибке правильное - шаблоны не могут иметь extern "C"
связь.
На базовом уровне шаблоны не могут иметь связи extern "C"
, потому что они несовместимы с C. В частности, шаблон не просто определяет отдельный класс или функцию, но семейство классов или функций, которые совместно используют один и тот же имя, но различаются по параметрам шаблона.
Только одна функция с заданным именем может быть объявлена extern "C"
. Это имеет смысл, когда вы думаете об искажении имени - в C функция foo
обычно вызывается либо foo
, либо _foo
в таблице символов. В C ++ может быть много перегрузок foo
, поэтому подпись включена в «искаженное» имя в таблице символов, и вы можете получить $3fooV
или foo$void
или что-то еще, чтобы отличить foo(void)
от foo(int)
и так далее. В C ++ одиночная перегрузка, помеченная extern "C"
, искажается в соответствии со схемой C для данной платформы, тогда как другие перегрузки сохраняют свое обычное искаженное имя.
Объявление шаблона extern "C"
потребует, чтобы все экземпляры были extern "C"
, что противоречит правилу extern "C"
только для одной функции с данным именем.
Хотя C не имеет искажения имени в течение struct
s, может быть только один struct
с данным именем. Таким образом, запрет на extern "C"
для шаблонов классов также имеет смысл - шаблон определяет семейство классов с одинаковым именем, которое соответствует C struct
?