Экстерн “C” только требуется на объявлении функции?

Я записал функцию C++, которую я должен вызвать из программы C. Для создания этого вызываемым из C я указал extern "C" на объявлении функции. Я затем скомпилировал код C++, но компилятор (Системы/C++ Dignus) генерировал скорректированное имя для функции. Так, это, по-видимому, не соблюдало extern "C".

Для разрешения этого добавил я extern "C" к функциональному определению. После этого компилятор генерировал имя функции, которое является вызываемым от C.

Технически, extern "C" только потребности, которые будут указаны на объявлении функции. Действительно ли это правильно? (FAQ C++ имеет хороший пример этого.) Необходимо ли также указать его на функциональном определении?

Вот пример для демонстрации этого:

/* ---------- */
/* "foo.h"    */
/* ---------- */

#ifdef __cplusplus
extern "C" {
#endif

/* Function declaration */
void foo(int);

#ifdef __cplusplus
}
#endif

/* ---------- */
/* "foo.cpp"  */
/* ---------- */

#include "foo.h"

/* Function definition */
extern "C"               // <---- Is this needed?
void foo(int i) {
  // do something...
}

Моей проблемой может быть результат неправильного кодирования чего-то, или я, возможно, нашел ошибку компилятора. В любом случае я хотел консультироваться с stackoverflow, чтобы удостовериться, что я знаю, который является технически "правильным" путем.

34
задан Marc.2377 24 September 2019 в 04:40
поделиться

4 ответа

' extern "C" ' не должен требоваться в определении функции, если он есть в объявлении и уже замечен при компиляции определения. В стандарте конкретно говорится (7.5 / 5 Спецификации связывания):

Функция может быть объявлена ​​без спецификации связывания после того, как явная спецификация связывания была обнаружена; на связь, явно указанную в предыдущем объявлении, такое объявление функции не влияет.

Тем не менее, я обычно добавляю ' extern «C» ' в определение, потому что это фактически функция с внешней связью "C". Многие люди ненавидят, когда в объявлениях используется ненужный, избыточный материал (например, установка virtual на переопределения методов), но я не один из них.

36
ответ дан 27 November 2019 в 17:07
поделиться

Редактировать:
Похоже, я неправильно понял вопрос. В любом случае, я попробовал:


// foo.cpp
/* Function definition */

#include "foo.h"

void foo(int i) {
 //do stuff
}
void test(int i)
{
// do stuff
}

// foo.h
#ifdef __cplusplus
extern "C" {
#endif

/* Function declaration */
void foo(int);

#ifdef __cplusplus
}
#endif

void test(int);

Используя команду nm , чтобы просмотреть символы из скомпилированного файла:


linuxuser$ nm foo.o
00000006 T _Z4testi
         U __gxx_personality_v0
00000000 T foo

Это явно предполагает, что имя функции, объявленной как extern «C», не искажено, а extern » Ключевое слово C "не требуется при определении.
Если бы для этого требовалось, что каждый код библиотеки C, написанный без extern «C», был бы непригоден для использования в программах на C ++.

1
ответ дан 27 November 2019 в 17:07
поделиться

extern «C» вокруг определения не требуется. Вы можете уйти, просто поместив это в декларацию. Одно примечание в вашем примере ...

#ifdef __cplusplus
extern "C" {
#endif

/* Function declaration */
void foo(int);

#ifdef __cplusplus
}
#endif

Ваш код ищет макрос препроцессора « __ cplusplus ».

Хотя это обычно реализуется, в зависимости от вашего компилятора это может быть определено или не определено. В вашем примере вы также используете extern «C» вокруг объявления, но там вы не проверяете макрос « __ cplusplus », поэтому я подозреваю это сработало, как только вы это сделали.

См. Комментарии ниже - Стандартный C ++ требует, чтобы макрос __ cplusplus был определен препроцессором.

1
ответ дан 27 November 2019 в 17:07
поделиться

Он должен быть где-то рядом. Компилятору необходимо знать, как использовать имя символа C и соглашения о вызовах при компиляции сайтов вызовов (которые могут видеть только объявление), а компилятор также должен знать, как сгенерировать имя символа C и использовать соглашения о вызовах C при компиляции само определение функции (которое может не видеть никаких других объявлений).

Теперь, если у вас есть объявление extern-C, которое видно из единицы перевода, в которой существует определение, вы можете уйти, оставив extern-C из определения, но я этого точно не знаю.

0
ответ дан 27 November 2019 в 17:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: