Подтвердить что ты не робот

Как работает внешняя декларация "С"?

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

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

4b9b3361

Ответ 1

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


Пример:

Скажем, у нас есть следующий код в файле с именем 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() сохраняет свое имя.

Ответ 2

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

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

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

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

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

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

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

Ответ 3

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

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

Ответ 4

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

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

Ответ 5

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

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

void foo();

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

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

Ответ 6

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

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

extern "C" void foo(int i);

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

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

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

#ifdef __cplusplus
extern "C" {
#endif

void foo(int i);

#ifdef __cplusplus
}
#endif

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

Ответ 7

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

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

int example(int alpha, char beta);

в C: _example

в С++: __Z7exampleic

Обновление. Поскольку примечания GManNickG в комментариях, шаблон изменения имени зависит от компилятора.

Ответ 8

extern "C", является ключевым словом для объявления функции с привязками C, потому что компилятор C и компилятор С++ переведут исходный код в другую форму в объектном файле:

Например, фрагмент кода выглядит следующим образом:

int _cdecl func1(void) {return 0}
int _stdcall func2(int) {return 0}
int _fastcall func3(void) {return 1}

32-битные компиляторы C переведут код в форме следующим образом:

_func1
[email protected]
@[email protected]

в cdecl, func1 будет переводить как _name '

в stdcall, func2 будет переводиться как ' _name @X'

в fastcall, func2 будет транслироваться как " @name @X"

' X "означает количество байтов параметров в списке параметров.

64-разрядное соглашение в Windows не имеет знака подчеркивания

В С++ вводятся классы, шаблоны, пространства имен и перегрузка операторов, поскольку для него не допускаются две функции с одинаковым именем, компилятор С++ предоставляет информацию о типе в имени символа,

например, фрагмент кода выглядит следующим образом:

int func(void) {return 1;}
int func(int) {return 0;}
int func_call(void) {int m=func(), n=func(0);}

Компилятор С++ преобразует код следующим образом:

int func_v(void) {return 1;}
int func_i(int) {return 0;}
int func_call(void) {int m=_func_v(), n=_func_i(0);}

'_ v' и '_i' - это информация типа 'void' и 'int'

Ответ 9

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

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

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