Должна ли внешняя "C" включать объявление или определение функции С++?
Я видел в файле cpp, что external "C" {...}
содержит определения нескольких функций.
Из https://isocpp.org/wiki/faq/mixing-c-and-cpp я предполагаю, что цель использования extern "C"
в файле cpp - сделать закрытые функции С++ доступными для использования в программе C,
Пример в ссылке показывает, что extern "C"
содержит только объявления функций С++, а не их определения
Просто объявите функцию С++ extern "C" (в коде С++) и вызовите он (из вашего кода C или С++). Например:
// C++ code:
extern "C" void f(int);
void f(int i)
{
// ...
}
Файл cpp, о котором я упоминал в начале, выглядит следующим образом:
// C++ code:
extern "C" {
void f(int i)
{
// ...
}
void g(int i)
{
// ...
}
}
Скрыть extern "C"
заключить объявления или определения функций С++?
Если да, то почему?
Ответы
Ответ 1
Он должен заключать объявления в файл заголовка, и определения должны быть заключены так долго, пока блок перевода скомпилирован с использованием компилятора С++, и пока декларация там не была видна.
Это никогда не ошибочно делает оба в коде С++.
Если компилятор c используется для компиляции определений функций, он не нужен (или лучше сказать, будет неправильный синтаксис, см. примечание ниже).
extern "C" {}
Управляет областью, в которой используется простая связь символов c. В противном случае будет применено С++ name mangling.
Примечание:
Так как extern "C" {}
это недопустимый синтаксис c, чтобы сделать это с компилятором c, вам нужно использовать его в #ifdef
:
MyHeader.h
:
#ifdef __cplusplus
extern "C" {
#endif
// ... c style function name declarations
void foo(int i);
#ifdef __cplusplus
} // extern "C"
#endif
Использование области extern "C" {}
фактически двоякое:
Экспорт кода С++ в C
Если приведенное выше скомпилировано с помощью компилятора c, оно появляется для него как декларация функции c. Если скомпилировано с компилятором С++, применяется ключевое слово extern
, и сглаживание имени С++ будет подавлено.
В отношении определения функция может использовать любые встроенные в нее функции С++:
extern "C" {
void foo(int x) {
std::vector v(x);
// ... blah, more c++ stuff
}
}
Обратите внимание, что объявление здесь не было включено. Это можно использовать в качестве метода, особенно полезно, когда вы хотите переопределить функции, открытые из библиотеки для слабой связи.
В случае включения MyHeader.h
область extern "C" {}
может быть опущена.
Импорт кода C из С++
Если приведенное выше объявление рассматривается в компиляторе С++, снова отменяется сглаживание имени С++, и любая ссылка на вызов foo()
будет разрешена компоновщиком с использованием имени символа функции c:
#include "MyHeader.h"
class MyClass {
public:
void bar(int y) {
// Use foo() as plain c function:
foo(y);
}
};
Реализация функции foo()
предоставляется из объектного файла (или архива), созданного с помощью компилятора c.
Ответ 2
[dcl.link]/5:
За исключением функций с С++-связью, объявление функции без спецификация связи не должна предшествовать первой привязке спецификации для этой функции. Функция может быть объявлена без спецификации связи после того, как спецификация явной привязки была видели; ссылка, явно указанная в предыдущей декларации, не затрагивается таким объявлением функции.
Обе версии отлично подходят для языковой привязки функции. Важная часть состоит в том, что первое объявление функции должно иметь extern "C"
.
Ответ 3
Лучше должны включать оба.
Чтобы убедиться, что символ не искажен, когда мы связываем код C на С++. мы используем extern блок "C".
Всякий раз, когда какой-либо код помещается в блок extern "C", компилятор С++ гарантирует, что имена функций не отображаются. i.e компилятор сгенерирует двоичный файл с именами без изменений, как это сделает компилятор C.
Mangling Поскольку С++ поддерживает перегрузку функций, в принципе может быть более одной функции с тем же именем. Таким образом, чтобы различать различные функции при генерации объектного кода, он изменяет имена, добавляя информацию о аргументах. Техника добавления дополнительной информации к именам функций называется Name Mangling.
Поскольку C не поддерживает перегрузку функции. Поэтому мы используем блок extern 'C' при связывании кода C на С++.
Ответ 4
Вы должны приложить как декларации, так и определения. Функции "C" и "С++" экспортируются с разными именами. Для создания правильного "C" внешнего имени в объектном файле extern "C"
требуется в cpp, иначе функция будет экспортироваться с С++ name mangling. Вы также должны заключить те extern "C" {
и соответствующие }
в #ifdef __cplusplus
и #endif
в заголовочный файл, который будет # включен в проект C, чтобы избежать ошибки компиляции C
Ответ 5
В тот же документ он показывает пример кода, который имеет extern "C"
в объявлении, но не в определении.
Если ваше определение "видит" объявление (т.е. объявление предшествует определению в блоке перевода), вам не нужно extern "C"
в определении. Но это не повредит - он будет игнорироваться компилятором.
Вот пример кода, приведенный в FAQ:
// This is C++ code
// Declare f(int,char,float) using extern "C":
extern "C" void f(int i, char c, float x);
// ...
// Define f(int,char,float) in some C++ module:
void f(int i, char c, float x)
{
// ...
}
Если по какой-либо причине вы решите не включать объявление перед определением, вам необходимо предоставить модификатор extern "C"
:
// This is C++ code
// Define f(int,char,float) in some C++ module:
extern "C" void f(int i, char c, float x)
{
// ...
}
Однако это противоречит большинству руководств стиля C и С++.