2017-01-29 9 views
7

Jeśli mamy dwa .c pliki .h oraz plik: main.c sub.c sub.h, gdzieC: wyjaśnienie na jednostki tłumaczeniowej

main.c

#include "sub.h" 
... 

sub.c

#include "sub.h" 
... 

Możemy skompilować program za pomocą: i)

gcc -o a.out main.c sub.c 

lub ii)

gcc -c main.c 
gcc -c sub.c 
gcc -o a.out main.o sub.o 

Biorąc pod uwagę to przypadek, czy jednostka wyjściowa preprocesor jeden lub dwa tłumaczenia (s)?

Jestem zdezorientowany, ponieważ: main.c zawiera sub.h, co oznacza, że ​​preprocesor wypisze jedną jednostkę kompilacji. Z drugiej strony przed utworzeniem pliku wykonywalnego tworzone są dwa pliki obiektów, main.o i sub.o, co pozwala mi myśleć, że "dwa pliki źródłowe, a więc dwie jednostki tłumaczeniowe".

Którą część nie rozumiem? lub gdzie popełniam błędy?

Odpowiedz

3

Oto co średnia C ma do powiedzenia na ten temat:

Plik źródłowy razem ze wszystkimi nagłówkami i pliki źródłowe zawarte za pośrednictwem dyrektywy przeróbki #include jest znany jako jednostki tłumaczeniowej przerób. Po wstępnym przetworzeniu, jednostka tłumaczenia wstępnego nazywana jest jednostką tłumaczeniową. [..] Wcześniej przetłumaczone tłumaczenie Jednostki mogą być przechowywane pojedynczo lub w bibliotekach.Oddzielne jednostki tłumaczeniowe programu komunikują się przez (na przykład) wywołania funkcji, których identyfikatory mają zewnętrzne powiązania, manipulowanie obiektami, których identyfikatory mają zewnętrzne powiązania lub manipulowanie plikami danych. Jednostki tłumaczeniowe mogą być oddzielnie tłumaczone, a następnie łączone w celu utworzenia programu wykonywalnego.

(Źródło: projekt normy C99, 5.1.1.1 §1)

Więc w obu przypadkach masz swój dwie jednostki tłumaczeniowe. Jedna z nich pochodzi z preprocessingu kompilatora main.c i wszystkiego, co jest zawarte w #include dyrektywach czyli sub.h i prawdopodobnie <stdio.h> i innych nagłówkach. Drugi pochodzi z kompilatora robiącego to samo z sub.c.

Różnica między pierwszym a drugim przykładem polega na tym, że w tym drugim przypadku jawnie przechowujesz "różne przetłumaczone jednostki tłumaczeniowe" jako pliki obiektów.

Należy zauważyć, że nie istnieje żadna reguła wiążąca jeden plik obiektowy z dowolną liczbą jednostek tłumaczeniowych. Łącznik GNU jest jednym z przykładów łącznika, który jest is capable of joining two .o files together.

Standard, o ile wiem, nie określa rozszerzenia plików źródłowych. Niezależnie od tego, w aspektach praktycznych, jesteś wolny do #include pliku .c na inny lub umieszczenie całego programu w pliku .h. Za pomocą gcc można użyć opcji -x c, aby wymusić traktowanie pliku .h jako punktu początkowego jednostki tłumaczeniowej.

Rozróżnienie dokonane tutaj:

Plik źródłowy razem ze wszystkimi nagłówkami i pliki źródłowe zawarte za pośrednictwem dyrektywy przeróbki #include [...]

dlatego nagłówek nie musi być plik źródłowy. Podobnie, zawartość <...> w dyrektywie #include nie musi być prawidłową nazwą pliku. Sposób, w jaki kompilator używa nazwanych nagłówków <...> i "...", jest zdefiniowany przez implementację.

6

Rozważ generowanie pliku wykonywalnego jako procesu dwuetapowego: Po pierwsze, każda jednostka tłumaczeniowa jest kompilowana do pliku obiektowego; nazwijmy to kompilatorem. Po drugie, pliki obiektowe są połączone razem z programem wykonywalnym; nazwijmy to linkerem.

"Jednostka tłumaczeniowa" to kwestia pierwszego kroku. Jednostką tłumaczeniową jest każdy plik, w którym rozpoczyna się kompilacja (tj. Która jest przekazywana do kompilatora). W większości IDE istnieją reguły, które deklarują, że każdy plik z rozszerzeniem .c lub .cpp jest przekazywany jako dane wejściowe do kompilatora, podczas gdy inne pliki nie. Dlatego pliki o rozszerzeniu .h, .hpp, .txt zwykle nie są przekazywane bezpośrednio do kompilatora.

W przykładzie main.c i sub.c prawdopodobnie jednostki tłumaczeniowe, natomiast sub.h ma jednostka tłumaczenie sama (to tylko jest „włączone” w innych jednostkach tłumaczeniowych i rozważane w trakcie ich opracowywania).

Otrzymujesz dwa pliki obiektów, po jednym dla każdej jednostki tłumaczeniowej. Te dwa pliki obiektów są następnie rozpatrywane przez linker.

Pamiętaj, że nawet plik .h może zawierać kompletny program; ale dopóki nie skonfigurujesz swojego środowiska, że ​​ten plik zostanie skompilowany samodzielnie, nie wygeneruje pliku obiektowego.