C++ extern keyword on functions. Dlaczego nie wystarczy dołączyć pliku nagłówka?

Jeśli dobrze to Rozumiem oznacza to

extern void foo();

Że funkcja foo jest zadeklarowana w innej jednostce translacyjnej.

1) Dlaczego nie po prostu #zawierać nagłówek, w którym ta funkcja jest zadeklarowana?

2) Skąd linker wie, gdzie szukać funkcji w czasie łączenia?

Edit: może powinienem wyjaśnić, że po powyższej deklaracji następuje Funkcja

foo();

Nigdy nie jest zdefiniowana w tej jednostce tłumaczeniowej.

Author: user199421, 2010-04-09

5 answers

1) może nie mieć pliku nagłówkowego. Ale tak, ogólnie rzecz biorąc, w przypadku dużych projektów, powinieneś mieć plik nagłówkowy, jeśli wiele jednostek tłumaczeniowych będzie używać tej funkcji(nie powtarzaj się).

2) linker przeszukuje wszystkie pliki obiektowe i biblioteki, o których powiedziano mu, aby znaleźć funkcje i inne symbole.

 26
Author: Brian Neal,
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-04-08 23:52:34

Nie, oznacza to, że funkcja {[1] } jest zadeklarowana z linkiem zewnętrznym . Połączenie Zewnętrzne oznacza, że nazwa foo odnosi się do tej samej funkcji w całym programie. Gdzie funkcja jest zdefiniowana nie ma znaczenia. Można go zdefiniować w tej jednostce tłumaczeniowej. Może być zdefiniowana w innej jednostce tłumaczeniowej.

Użycie słowa kluczowego extern, Jak pokazano w przykładzie, jest zbędne. Funkcje zawsze mają domyślnie zewnętrzne połączenie. Powyższe jest w 100% równoważne just

void foo();

Jak dla linker, gdy linker łączy program ze sobą, po prostu wygląda wszędzie . Przegląda wszystkie definicje, dopóki nie znajdzie definicji foo.

 15
Author: AnT,
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-04-09 00:07:29

Jak już stwierdzili inni, słowo kluczowe extern jest używane do określenia, że nazwa (zmienna lub funkcja) ma zewnętrzne powiązanie, co oznacza, że nazwa odnosi się do tego samego obiektu w całym programie. Jest to również domyślne dla zmiennych i funkcji zdefiniowanych w obszarze pliku, więc takie użycie jest zbędne.

Jest jeszcze inne użycie słowa kluczowego extern, które wygląda tak:

extern "C" void foo();

Oznacza to, że funkcja foo będzie linkowana przy użyciu konwencji C do linkowania (może dlatego, że jest funkcją zdefiniowaną w bibliotece C lub jest funkcją przeznaczoną do wywoływania przez programy C).

 14
Author: goedson,
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
2018-05-06 16:43:15

To już oznacza, że bez słowa kluczowego extern. Funkcje mają domyślnie powiązania zewnętrzne, chyba że zadeklarujesz je jako statyczne.

Używanie prototypów funkcji jest w porządku, ale łatwo się pomylić. Błąd linkera, który otrzymasz, nie jest łatwy do zdiagnozowania, gdy zmienisz definicję implementacji funkcji. Linker nie wie, gdzie szukać, Twoim zadaniem jest dać mu plik obiektowy, który zawiera definicję funkcji, aby był szczęśliwy.

 8
Author: Hans Passant,
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-04-09 00:01:08

1) Nie wiem po co mi to do funkcji. Może ktoś inny może wkroczyć.

2) linker określa to przechodząc przez wszystkie pliki obiektowe i sprawdzając symbole wewnątrz KAŻDEGO pliku obiektowego. Zakładam, że w zależności od Twojego linkera, dokładna kolejność wyszukiwania może się różnić.

Dla ld GNU binutils wszystkie pliki i biblioteki obiektów, które pojawiają się w wierszu poleceń linkera po obiekcie zawierającym brakujący symbol, są przeszukiwane od lewej do prawej i od pierwszego znalezionego symbolu jest wybierany.

przykład 1:

  • a . o -- używa foo (), bar ()
  • liba -- provides bar ()
  • libb -- dostarcza foo ()

$ > ld a. o-la-lb

Spowoduje przeszukiwanie a. o w poszukiwaniu niezdefiniowanych symboli. Następnie ld przejdzie przez libs od lewej do prawej, aby wyszukać te symbole i znajdzie bar w liba i foo w libb.

Może to prowadzić do dziwnych problemów z kołowymi zależnościami:

przykład 2:

  • a . o -- uses bar ()
  • liba -- dostarcza bar (), używa foo ()
  • libb -- dostarcza foo (), używa bar ()

Teraz istnieje okrężna zależność między liba i libb i linkowanie się nie powiedzie:

$ > ld a. o-la-lb

Ponieważ podczas przeszukiwania niezdefiniowanych symboli w libb, ld stwierdzi, że nie ma innej lib po prawej stronie-lb, która dostarczy Ten symbol. Można to ustalić na co najmniej dwa sposoby:

1) link liba dwa razy: $ > ld a. o-la-lb-la

2) Użyj funkcji grupowania ld $ > ld a. o --start-group-la-lb --end-group

W przypadku 2), grupowanie nakazuje ld przeszukiwać wszystkie symbole we wszystkich bibliotekach należących do tej grupy.

 2
Author: BjoernD,
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-04-09 00:04:50