Является ли extern "C" обязательным только для объявления функции?

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

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

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

Вот пример, чтобы продемонстрировать это:

/* ---------- */
/* "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, чтобы убедиться, что я знаю, что технически является "правильным" способом.

25
задан 04 сент. '09 в 21:30
источник поделиться
6 ответов

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

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

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

29
ответ дан 04 сент. '09 в 21:48
источник

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


// 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" , был бы непригодным для использования в программах на С++.

1
ответ дан 04 сент. '09 в 22:08
источник

Просто столкнулся с такой ситуацией... Не приятный опыт.

В одном из моих файлов c было объявлено следующее:

void unused_isr(void) {}
void ADC_IRQHandler(void)     __attribute__ ((weak, alias("unused_isr"))); 

Далее где-то в файле cpp я определил:

void ADC_IRQHandler(void) {                                                                                  
    ...
}

И я забыл изменить форвардную декларацию на:

void ADC_IRQHandler(void);

Мне потребовалось некоторое время, прежде чем я понял, что делаю все правильно в отношении преобразования AD, но мне не удалось добавить выражение "extern C" в определение!

extern "C" void ADC_IRQHandler(void) {                                                                                  
    ...
}

Только мои два цента, почему при определенных обстоятельствах может быть полезно иметь привычку добавлять его в определение.

1
ответ дан 07 нояб. '14 в 12:21
источник

Я думаю, что это нужно разъяснить здесь, так как у меня просто была аналогичная проблема, и мне потребовалось некоторое время, чтобы понять это в моей голове, только Брукс Мозес коснулся этого должным образом, и я думаю, что это должно быть указано более ясно...

В итоге заголовок может вас отбросить, все компиляторы видят файл cpp, и если заголовок не включен в extern "C" обратно в ваш cpp (что я обычно вижу), то extern "C" должен быть в файле cpp где-нибудь (либо в определении, либо в другом объявлении), поэтому компилятор CXX может знать, чтобы сделать его с помощью C linkage, компилятор не заботится о заголовке, только компоновщик.

1
ответ дан 21 янв. '15 в 7:04
источник

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

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

0
ответ дан 04 сент. '09 в 21:32
источник

extern "C" вокруг определения не требуется. Вы можете уйти, просто положив его на объявление. Одна заметка в вашем примере...

#ifdef __cplusplus
extern "C" {
#endif

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

#ifdef __cplusplus
}
#endif

Ваш код ищет макрос препроцессора "__cplusplus".

<ы > Хотя это обычно реализуется, в зависимости от вашего компилятора, это может быть или не быть определено. В вашем примере вы также используете extern "C" вокруг объявления, но там вы не проверяете макрос "__cplusplus", поэтому я подозреваю, что он сработал, как только вы это сделали. С >

См. комментарии ниже. Стандартный С++ требует, чтобы макрос __cplusplus определялся препроцессором.

0
ответ дан 04 сент. '09 в 22:54
источник

Другие вопросы по меткам или Задайте вопрос