Допустим, у меня есть файл заголовка C++, который выглядит так:
/* cpp_header.h */
#include <vector>
#ifdef __cplusplus
extern 'C' {
#endif
void foo1(int x);
void foo2(int y);
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus
/* function I don't want visible to C compiler */
void foo3(vector<int> &v);
#endif
Теперь я включаю этот файл заголовка в файл заголовка C:
/* c_header.h - all implementation built with C compiler */
#include <stdio.h>
#include "cpp_header.h"
int cfoo();
int cfoo1(int x);
Теперь предположим, что я хочу использовать cfoo () и cfoo1 () в другом файле cpp, и я делаю что-то вроде этого:
/* crazy.cpp - this will cause a build breakage */
extern 'C' {
#include "c_header.h"
}
#include <iostream>
int main() {
cfoo();
cfoo1(88);
std::cout << "Yes, this is crazy!" << std::endl;
return 0;
}
Приведенный выше код никогда не будет построен, потому что foo3 () в первом файле заголовка будет жаловаться на то, что мы пытаемся создать шаблон с C-linkage. Это произошло из-за того, что мы заключили весь файл c_header.h в защитную оболочку extern C. Есть ли способ добавить что-то, что может изменить защиту «extern C», чтобы foo3 был построен со связью C++. Может быть, примерно так:
#ifdef __cplusplus
extern 'CPP' { /* re-enable C++ name-mangling/linkage */
foo3(vector<int> &v);
}
Спасибо.
extern "C"
должен заключать только объявления предназначен для связи C. То есть ваш c_header.h
должен выглядеть как ваш cpp_header.h
(с #ifdef __cplusplus
- extern "C"
), чтобы компилятор C++ видел функции C; у вашего cpp_header.h
не должно быть ничего подобного (потому что это C++), и у вас не должно быть extern "C"
в вашем main.cpp (потому что внутренняя обработка этого материала зависит от заголовков).
Вы можете включить cpp_header напрямую, без extern "C"
, прежде чем включать c_header, при условии, что у вас есть средства защиты или какой-либо другой механизм для выполнения этой работы.
Не требует ли extern строковый литерал? extern 'C'
скорее всего недействителен и должен быть extern "C"
.
Формат extern
- extern string-literal
. "C"
- это строковый литерал, 'C'
- нет.
@Aconcagua: Если это заголовок C++, по определению не предоставляет функции с интерфейсом C. (Тогда это был бы заголовок C или пример плохого дизайна крайне - выставление интерфейса C в заголовке, который не может использоваться компилятором C?)
@ Аконкагуа: Понятия не имею, о чем вы говорите. Библиотека C, которая хочет, чтобы ее заголовки использовались C++, помещает свои заголовки в #ifdef __cplusplus
/ extern "C"
. Библиотека C++, которая хочет использовать C, делает то же самое для заголовков C (но также может иметь заголовки, специфичные для C++). Смешивание Объявления C и C++ в одном заголовке не служат практической цели, так как в любом случае могут использоваться только C++. (В любом случае вам нужно будет где-то разместить этот заголовок C, и вы просто дублируете его содержимое ...)
@DevSolar Давай забудем об этом ... Кажется, все дело в разных определениях того, что есть что ...
@ T.C. - Большое спасибо, это то, что я искал. Короче говоря, кто-то поместил заголовочный файл C++ в файл заголовка C. Упомянутый файл заголовка C компилируется внутри исходного файла CPP, обернутого вокруг внешней защиты "C". Это не было проблемой, потому что заголовочный файл C++ содержал только API-интерфейсы в стиле C и также был защищен с помощью #ifdef__cplusplus и extern 'c'. Проблема началась, когда я хотел добавить API с функцией C++ (например, void foo (vector <int> & v) в файл заголовка C++. Я рекомендовал, чтобы мы все сделали правильно, но исправление кода потребует времени. извините за форматирование
Как объясняется в https://en.cppreference.com/w/cpp/language/language_linkage, вы можете использовать как extern "C"
, так и extern "C++"
(последний является значением по умолчанию для C++).
Здесь также говорится
When language specifications nest, the innermost specification is the one that is in effect.
Так
extern "C" {
extern "C++" void foo3(vector<int> &v);
}
должно работать нормально.
Тем не менее, лучшим решением было бы добавить части #ifdef __cplusplus
/ extern "C" {
к объявлениям в самом заголовке C. Тогда вам не нужно оборачивать #include
в свой основной файл cpp.
Как в:
/* c_header.h - all implementation built with C compiler */
#include <stdio.h>
#include "cpp_header.h"
#ifdef __cplusplus
extern "C" {
#endif
int cfoo();
int cfoo1(int x);
#ifdef __cplusplus
}
#endif
Тогда все потребители могут просто #include "c_header.h"
, независимо от того, используют ли они C++ или C.
Спасибо большое. Именно то, что я искал.
Ну да, есть
extern "C++"
. Но зачем вы вообще оборачиваете заголовок include вextern "C"
?