Когда использовать extern "C"? - PullRequest
5 голосов
/ 03 ноября 2011

Я знаю, как использовать extern "C", но каковы условия, когда вы должны его использовать?

extern "C" говорит компилятору C ++ не выполнять манипулирование именами код в фигурных скобках. Это позволяет вам вызывать функции C из в C ++.

Например:

#include <string.h>

int main()
{
    char s[] = "Hello";
    char d[6];

    strcpy_s(d, s);
}

Хотя это прекрасно компилируется на VC ++. Но иногда это записывается как:

extern "C" {   
#include <string.h>  
}

Не вижу смысла. Можете ли вы привести реальный пример, где extern "C" необходим?

Ответы [ 6 ]

7 голосов
/ 03 ноября 2011

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

Например, скажем, у вас есть библиотека widget, которая была скомпилирована с помощью компилятора C, так что ее опубликованный интерфейс не искажен.

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

Однако, поскольку вы будете запрашивать что-то вроде function@intarray_float_charptr, а библиотека widget будет публиковать только function, у вас возникнут проблемы.

Однако, если вы включите его с:

extern "C" {
    #include "widget.h"
}

ваш компилятор будет знать, что он должен попытаться использовать function, не искаженную версию.

Вот почему в заголовочных файлах для C, предназначенных для включения в программы C _ или C ++, вы увидите такие вещи, как:

#ifdef __cplusplus
    extern "C" {
#endif

// Everything here works for both C and C++ compilers.

#ifdef __cplusplus
    }
#endif

Если вы используете компилятор C для включения этого, строки #ifdef приведут к исчезновению содержимого extern "C". Для компилятора C ++ (где определено __cplusplus) все будет не повреждено.

4 голосов
/ 03 ноября 2011

Вот конкретный пример того, как что-то сломалось, и нужно extern "C", чтобы исправить.

module.h

int f(int arg);

module.c:

int f(int arg) {
  return arg + 1;
}

main.cpp

#include "module.h"

int main() {
  f(42);
}

Поскольку я смешиваю C и C ++, это не будет связывать (из двух объектных файлов только один будет знать f под его искаженным именем C ++).

Пожалуй, самый простой способ исправить это - сделать заголовочный файл совместимым с C и C ++:

module.h:

#ifdef __cplusplus
  extern "C" {
#endif

int f(int arg);

#ifdef __cplusplus
  }
#endif
4 голосов
/ 03 ноября 2011

Одно очень распространенное использование extern "C" при экспорте функции из библиотеки. Если вы не отключите искажение имен в C ++, в противном случае клиентам вашей библиотеки будет очень сложно назвать вашу функцию. И точно так же, когда вы идете в другом направлении, когда вы импортируете функцию, которая была экспортирована с привязкой C.

1 голос
/ 03 ноября 2011

Если внутри вашего кода C ++ вы #include заголовок для внешней библиотеки (кодируется в C), и если есть функции не объявлены extern "C", они не будут работать (вы получитенеопределенная ссылка во время ссылки).

Но в наши дни люди, кодирующие библиотеки C и предоставляющие вам заголовочные файлы, как правило, знают об этом и часто помещают extern "C" в их заголовочный файл (соответственно защищенный #ifdef __cplusplus)

Возможно, лучший способ понять это - использовать (при условии, что у вас система Linux) утилиту nm, чтобы показать вам (не исправленные) имена, используемые в библиотеке или исполняемом файле.

1 голос
/ 03 ноября 2011

Если вы создаете двоичную библиотеку A, которая предоставляет функцию, которую вы хотели бы вызвать из двоичного файла B.

Представьте, что A - это A.dll, а B - это B.exe, и вы работаете в системе Windows.

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

См: http://en.wikipedia.org/wiki/Application_binary_interface http://en.wikipedia.org/wiki/Name_mangling#Name_mangling_in_C.2B.2B

1 голос
/ 03 ноября 2011

Когда вы связываетесь с библиотеками, написанными на C extern, велит компилятору не украшать имена, чтобы компоновщик мог найти функции.В C ++ имена функций и др. Содержат информацию для компоновщика, например, типы аргументов и размеры, содержащиеся в имени.

...