Jak działa deklaracja extern "C"?

Biorę udział w kursie języków programowania i mówimy o extern "C" deklaracji.

Jak ta deklaracja działa na głębszym poziomie niż " interfejsy C i C++"? Jak to wpływa na wiązania, które odbywają się również w programie?

 22
Author: Jonathan Leffler, 2010-03-08

9 answers

extern "C" służy do zapewnienia, że poniższe symbole nie są zniekształcone (dekorowane).


Przykład:

Załóżmy, że mamy następujący kod w pliku o nazwie test.cpp:

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

int bar() {
  return 1;
}

If you run gcc -c test.cpp -o test.o

Spójrz na nazwy symboli:

00000010 T _z3barv

00000000 T foo

foo() zachowuje swoją nazwę.

 44
Author: Bertrand Marron,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-08 18:00:15

Spójrzmy na typową funkcję, która może kompilować zarówno w C, jak i C++:

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

Teraz w C funkcja nazywa się wewnętrznie "_Add". Natomiast funkcję C++ nazywa się czymś zupełnie innym wewnętrznie za pomocą systemu nazwanego namaglowaniem. To w zasadzie sposób na nazwanie funkcji tak, aby ta sama funkcja o różnych parametrach miała inną nazwę wewnętrzną.

Więc jeśli Add() jest zdefiniowane w add.c, i masz prototyp w dodatku.h będziesz miał problem, jeśli spróbujesz aby dodać.h w pliku C++. Ponieważ kod C++ szuka funkcji o nazwie innej niż ta w add.c otrzymasz błąd łącznika. Aby obejść ten problem, musisz dołączyć add.c tą metodą:

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

Teraz kod C++ połączy się z _Add zamiast z nazwą wersji mangled C++.

To jedno z zastosowań wyrażenia. Podsumowując, jeśli potrzebujesz skompilować kod, który jest ściśle C w programie C++ (za pomocą instrukcji include lub w inny sposób), możesz trzeba owinąć go z zewnątrz "C" {... deklaracja.

 22
Author: Cthutu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-08 17:56:54

Kiedy oznaczasz blok kodu extern "C", mówisz systemowi, aby używał połączenia w stylu C.

Wpływa to głównie na sposób, w jaki linker zniekształca nazwy. Zamiast używać mangling nazw w stylu C++ (co jest bardziej skomplikowane, aby obsługiwać przeciążenia operatorów), otrzymujesz standardowe nazewnictwo w stylu C z linkera.

 9
Author: Reed Copsey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-08 18:16:21

W C++ nazwa/symbol funkcji jest zmieniana na coś innego, tak że różne klasy / przestrzenie nazw mogą mieć funkcje o tych samych podpisach. W języku C wszystkie funkcje są definiowane globalnie i nie jest potrzebny taki niestandardowy proces zmiany nazwy.

Aby C++ i C ze sobą rozmawiały, "extern C"nakazuje kompilatorowi nie używać konwencji C.

 5
Author: gilbertc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-08 18:14:40

Należy zauważyć, że extern "C" modyfikuje również typy funkcji. Nie tylko modyfikuje rzeczy na niższych poziomach:

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

void foo();

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

Typ &foo nie jest równy typowi oznaczonemu przez typedef (chociaż kod jest akceptowany przez niektóre, ale nie wszystkie Kompilatory).

 5
Author: Johannes Schaub - litb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-08 21:39:37

Extern C wpływa na wymazywanie nazw przez kompilator C++. Jest to sposób na to, aby kompilator C++ nie zmieniał nazw, a raczej zmieniał je w taki sam sposób, jak kompilator C. W ten sposób łączy C i C++.

Jako przykład:

extern "C" void foo(int i);

Pozwoli na zaimplementowanie funkcji w module C, ale pozwoli na wywołanie jej z modułu C++.

Problem pojawia się przy próbie wywołania przez moduł C funkcji C++ (Oczywiście C nie może używać klas C++) zdefiniowanych w module C++. Kompilator C nie lubi extern "C".

Więc musisz użyć tego:

#ifdef __cplusplus
extern "C" {
#endif

void foo(int i);

#ifdef __cplusplus
}
#endif

Teraz, gdy to pojawi się w pliku nagłówkowym, zarówno kompilatory C i c++ będą zadowolone z deklaracji i może być teraz zdefiniowany w module C lub C++ i może być wywołany zarówno przez kod C i C++.

 4
Author: quamrana,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-08 18:06:09

Extern " C " oznacza, że załączony kod używa linkowania w stylu C i namaglowania nazw. C++ używa bardziej skomplikowanego formatu mangling nazw. Oto przykład:

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

int example(int alpha, char beta);

W C: _example

W C++: __Z7exampleic

Update: jak zauważa GManNickG w komentarzach, wzorzec manglingu nazw jest zależny od kompilatora.

 3
Author: Harvey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-08 16:08:13

Extern "C", jest słowem kluczowym do deklarowania funkcji z powiązaniami C, ponieważ kompilator C i kompilator C++ będą tłumaczyć źródło na inną formę w pliku obiektowym:

Na przykład fragment kodu jest następujący:

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

32-bitowe kompilatory C będą tłumaczyć kod w następujący sposób:

_func1
_func2@4
@func3@4

W cdecl func1 przetłumaczy jako ' _name '

Func2 w stdcall będzie tłumaczony jako ' _name@X '

W fastcall func2 będzie translate as ' @ name@X '

'X ' oznacza liczbę bajtów parametrów na liście parametrów.

64-bitowa Konwencja w systemie Windows nie ma wiodącego podkreślenia

W C++ wprowadzono klasy, szablony, przestrzenie nazw i przeciążenia operatorów, ponieważ nie są dozwolone dwie funkcje o tej samej nazwie, kompilator C++ dostarcza informacji o typie w nazwie symbolu,

Na przykład fragment kodu jest następujący:

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

Kompilator C++ będzie Przetłumacz kod w następujący sposób:

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' _i 'to informacje typu 'void ' i'int'

 0
Author: Dongwei Wang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-30 13:42:01

Oto cytat z msdn

" słowo kluczowe extern deklaruje zmienną lub funkcję i określa, że ma ona odnośnik zewnętrzny (jej nazwa jest widoczna z plików innych niż ten, w którym została zdefiniowana). Podczas modyfikowania zmiennej, extern określa, że zmienna ma statyczny czas trwania (jest przydzielana, gdy program się rozpoczyna, a dealokowana, gdy program się kończy). Zmienna lub funkcja może być zdefiniowana w innym pliku źródłowym lub później w tym samym pliku. Deklaracje zmiennych i funkcje w zakresie plików są domyślnie zewnętrzne."

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

 -2
Author: Joe Pitz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-08 17:52:02