Как делает экстерна “C” работа объявления?

Я беру курс языков программирования, и мы говорим о extern "C" объявление.

То, как это объявление работает на более глубоком уровне кроме "его, соединяет интерфейсом с C и C++"? Как это влияет на привязку, которая происходит в программе также?

27
задан Jonathan Leffler 31 May 2016 в 02:13
поделиться

8 ответов

extern "C" используется для того, чтобы следующие символы не были mangled (украшены).


Пример:

Допустим, у нас есть следующий код в файле под названием test.cpp:

extern "C" {
  int foo() {
    return 1;
  }
}

int bar() {
  return 1;
}

Если вы выполните gcc -c test.cpp -o test.o

Посмотрите на имена символов:

00000010 T _Z3barv

00000000 T foo

foo() сохраняет свое имя.

47
ответ дан 28 November 2019 в 04:10
поделиться

В C ++ имя / символ функций фактически переименованы во что-то другое, так что разные классы / пространства имен могут иметь функции с одинаковыми сигнатурами. В C все функции определены глобально, и такой настраиваемый процесс переименования не требуется.

Чтобы заставить C ++ и C взаимодействовать друг с другом, extern C указывает компилятору не использовать соглашение C.

5
ответ дан 28 November 2019 в 04:10
поделиться

Вот цитата из msdn

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

http://msdn.microsoft.com/en-us/library/0603949d%28VS.80%29.aspx

-2
ответ дан 28 November 2019 в 04:10
поделиться

Следует отметить, что extern "C" также изменяет типы функций. Он изменяет не только вещи на нижних уровнях:

extern "C" typedef void (*function_ptr_t)();

void foo();

int main() { function_ptr_t fptr = &foo; } // error!

Тип &foo не равен типу, обозначенному typedef (хотя код принимается некоторыми, но не всеми компиляторами).

5
ответ дан 28 November 2019 в 04:10
поделиться

Давайте посмотрим на типичную функцию, которая может компилироваться как в C, так и в C ++:

int Add (int a, int b)
{
    return a+b;
}

Теперь в C функция внутренне называется "_Add". В то время как функция C ++ вызывается чем-то совершенно другим внутри, используя систему, называемую изменением имен. По сути, это способ назвать функцию так, чтобы одна и та же функция с разными параметрами имела другое внутреннее имя.

Итак, если Add () определен в add.c, и у вас есть прототип в add.h, вы столкнетесь с проблемой, если попытаетесь включить add.h в файл C ++. Поскольку код C ++ ищет функцию с именем, отличным от имени в add.c, вы получите ошибку компоновщика. Чтобы обойти эту проблему, вы должны включить add.c этим методом:

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

Теперь код C ++ будет связываться с _Add вместо версии с измененным именем C ++.

Это одно из применений выражения. В итоге, если вам нужно скомпилировать код, который строго является C в программе на C ++ (с помощью оператора include или каким-либо другим способом), вам нужно обернуть его объявлением extern "C" {...}.

25
ответ дан 28 November 2019 в 04:10
поделиться

extern C влияет на изменение имени компилятором C ++. Это способ заставить компилятор C ++ не искажать имена или, скорее, искажать их так же, как компилятор C. Так он взаимодействует с C и C ++.

В качестве примера:

extern "C" void foo(int i);

разрешает реализацию функции в модуле C, но позволяет вызывать ее из модуля C ++.

Проблема возникает при попытке заставить модуль C вызывать функцию C ++ (очевидно, C не может использовать классы C ++), определенную в модуле C ++. Компилятор C не любит extern «C» .

Итак, вам нужно использовать это:

#ifdef __cplusplus
extern "C" {
#endif

void foo(int i);

#ifdef __cplusplus
}
#endif

Теперь, когда это появляется в файле заголовка, компиляторы C и C ++ будут довольны объявлением, и теперь оно может быть определено в модуле C или C ++ и может вызываться как кодом C, так и кодом C ++.

4
ответ дан 28 November 2019 в 04:10
поделиться

extern «C» означает, что вложенный код использует связывание в стиле C и изменение имен. C ++ использует более сложный формат изменения имен. Вот пример:

http://en.wikipedia.org/wiki/Name_mangling

int example(int alpha, char beta);

в C: _example

в C ++: __ Z7exampleic

Обновление: Как отмечает GManNickG в комментариев, шаблон изменения имени зависит от компилятора.

3
ответ дан 28 November 2019 в 04:10
поделиться

Когда вы помечаете блок кода с помощью extern «C», вы говорите системе использовать связывание в стиле C.

Это, в основном, влияет на способ, которым компоновщик искажает имена. Вместо того, чтобы использовать изменение имени в стиле C ++ (которое более сложно для поддержки перегрузок операторов), вы получаете стандартное именование в стиле C из компоновщика.

9
ответ дан 28 November 2019 в 04:10
поделиться