Zawartość plików nagłówkowych biblioteki standardowej

0

Hej

Otoz otworzylem sobie i zerknalem na plik naglowkowy biblioteki c, stdlib.h <- a chyba ten naglowek udostepnia wiele funkcji a jak patrzylem to ma tylko prawie 1000 linijek kodu, o co chodzi ? Moze odwoluje sie do jakis innych plikow w internecie albo do innych plikow ? jak tak to do jakich.

0

lekcja na dzis?

Statyczne i dynamiczne bibloteki.

Masz dostep tylko do headerow (.h) a linker wie ze implementacja jest w innym pliku.

1

Plik nagłówkowy nie zawiera implementacji funkcji, a tylko ich deklaracje. Definicje tych funkcji umieszczane są w odpowiadających plikach źródłowych(*.c) i zwykle dostarczane do użytkownika w formie skompilowanej, zaszyte gdzieś w kompilatorze.

0

Aha, czyli moj kompilator gcc jest juz skompilowany razem z tymi funkcjami.

0

Twój kompilator, oprócz tego że zajmuje się kompilacją kodu, wywołuje także wiele narzędzi dla niego zewnętrznych. Jednym z takich narzędzi jest linker (pol. konsolidator). Jak kompilator buduje plik z końcówką *.o, to deklaruje w tych plikach że będą używane wywołania (np. printf(), getc()...). Robi to na podstawie *.h.
Linker jak składa Ci program do postaci uruchamialnej z plików *.o, to łączy te pliki z biblioteką. Biblioteka to także plik binarny. Biblioteki (nie wiem jaki masz system) mają końcówki *.dll (win), *.so (*nix), *.lib (już raczej nie zobaczysz ale win), *.a (*nix). To w bibliotece masz te wszystkie wywołania których użyłeś w programie.
Ja uprościłem oczywiście żeby nie wchodzić w niepotrzebne szczegóły ale ... na pewno nie okłamałem :-)
Czyli, dokładnie, te wszystkie wywołania których używasz z *.h przychodzą z biblioteką standardową :-)

0

Czyli skad gcc bierze linker ? oraz co to te pliki *.o

2

Linker gcc bierze z narzędzi nazywanych binutils. W zależności od tego w jakim systemie pracujesz, albo zobaczysz tę część oprogramowania jako oddzielną (np. w GNU/Linux), lub nie (np. używając MinGW pod Windows). W tych narzędziach jest np. asembler, programy diagnostyczne itp..
Pliki *.o, tworzone są przez Twoje IDE (nie wiem w czym pracujesz), poprzez wywołanie kompilatora gcc z przełącznikiem -c. Nawet pewnie tego nie zobaczysz jako oddzielny etap :-)
Np. ręczna kompilacja programu w C, złożonego z 2 plików to:

gcc -c utils.c 
gcc -c main.c
gcc -o main main.o utils.o

W 1 linii powstaje plik utils.o, w 2 main.o. W 3 linii kompilator wywołuje program linkera do wykonania pracy związanej ze zbudowaniem programu do uruchomienia w systemie.

Taka praca etapami ma bardzo duży sens bo pozwala budować duże oprogramowanie i automatyzować czynności.

Przy budowanie *.o, pod spodem są jeszcze wykonywane etapy budowania programu :-) Na pierwszym etapie są rozwijane makra i włączane pliki *.h (zatrzymasz kompilator gcc na tym etapie przez -E ), na drugim tworzony jest program w assemblerze (-S) a dopiero na końcu asember buduje plik *.o :-)

Linker jak łączy *.o w jeden program, dodaje kod rozruchowy (swój własny *.o uruchamiający dla danego systemu) i łączy program ... z bibliotekami..

Słuchaj.. jak tak dalej mam pisać to elaborat wyjdzie... :-) Mam nadzieję że na tym etapie wystarczy :-)

0

tak, pomogles dzieki :)
Bo ja wlasnie kompiluje zawsze recznie programem g++, tylko ze ja na razie pisze tylko programy jedno plikowe to wyglada to tak g++ program.c i mam pytanie, czy da sie uruchomic g++ z takimi parametrami albo zrobic cos innego zeby pokazywal mi w outpucie kompilacji mojego programu co po kolei robi, te etapy co napisales, zeby to wszystko mi w terminalu pokazywal ?

0

Zaraz zaraz. Wątek w dziale C. Więc przykłady w C :-)

Zakładam że pracujesz w systemie GNU/Linux lub z kompilatorem MinGW i masz skonfigurowane poprawnie ścieżki do narzędzi.

Puryści proszę nie bić za koszmarny maksymalnie kod. Ma być demonstracją co i jak się rozwija, co widać w ABI itp. Z poprawnym tworzeniem kodu nie ma nic wspólnego a ty początkujący nie wzoruj się na takim tworzeniu oprogramowania.
Oto przykład main.c:

#include <stdio.h>

#define OTO_STALA 5
#define OTO_MAKRO(x) printf("Jestem makro OTO_MAKRO i przekazano mi %d\n", x);

/* Zmienne różne... */
int globalna_zerowana;
int globalna = 12;
static int statyczna_zerowana; 
static int statyczna = 333;

typedef long typek_t;

/* Funkcje różne ... */
void funkcja_z_int(int argument) {
    printf("Oto ja %s z int = %d\n", __FUNCTION__, argument);
}

void funkcja() {
    ;
}

static void funkcja_statyczna() {
    ;
}

int main(void) {

    typek_t zmienna = 7682892;

    printf("Zmienne ...\n");
    printf("globalna_zerowana = %d\n", globalna_zerowana);
    printf("globalna = %d\n", globalna);
    printf("statyczna_zerowana = %d\n", statyczna_zerowana);
    printf("statyczna = %d\n", statyczna);
    printf("A teraz sobie wywołamy... \n");
    funkcja_z_int(12);
    printf("A teraz funkcja()\n");
    funkcja();
    printf("A teraz funkcja_statyczna()\n);
    funkcja_statyczna();
    printf("A teraz makro\n");
    OTO_MAKRO(OTO_STALA);
    printf("typek_t zmienna = %ld\n", zmienna);
    return 0;
}

Zatrzymanie kompilatora na etapie (1)włączenia plików i rozwinięcia makr:

gcc -E -o main.E main.c

Zatrzymanie na etapie generowania (2)asemblera po (1) włączeniu i rozwinięciu makr:

gcc -S -o main.S main.c

Zatrzymanie na etapie budowy (3)pliku obiektowego po (1)włączeniu i rozwinięciu makr i (2)wygenerowaniu asemblera:

gcc -c -o main.o main.c

Przy tym ostatnim możesz nie podawać -o bo sam wie że ma zbudować main.o
Zatrzymanie na etapie zbudowanego programu po (1) , (2) i (3):

gcc -o main main.c

Zerknij teraz do main.E i main.S ... tylko się nie przeraź (tym pierwszym). Poszukaj makr, zmiennych, funkcji... zobacz co się z nimi dzieje.

A teraz ABI (ang. Application Binary Interface)

Wyświetlenie symboli w pliku *.o:

objdump -t main.o

Wyświetlenie symboli ładowanych dynamicznie z pliku main:

objdump -T main

Wyświetlenie sekcji w pliku *.o

objdump -x main.o

Dezasemblacja pliku main:

objdump -d main

Tryb "gadatliwego" linkera przy kompilacji: (tu zobaczysz jakie dodatkowe pliki włącza, skąd i kiedy.. )

gcc -Wl,--verbose -o main main.c

Także popatrz czy "widać" static, jakie funkcje widać itp..

I na koniec, wisienka :-) Kompilowanie programu w trybie gdzie będziesz widział jak wygląda program w C i asembler:

gcc -g1 -o main main.c
objdump -S main

To są bardzo szerokie zagadnienia. Każdego opisać nie sposób w poście na forum. Zaraz będziesz pytał co oznacza g,w,F,O w wyjściu komend. Odsyłam do manuali i dokumentacji. Ale już po tym co napisałem, możesz zrozumieć jak działa kompilator :-)
Smacznego :-)

1

Szczególowy opis tego co powinno dziać się podczas kompilacji z punktu widzenia języka jest w standardzie. C11 - 5.1.1.2 "Translation phases".

Dla GCC tutaj masz skrócony opis kolejnych kroków kompilacji z punktu widzenia kompilatora: https://gcc.gnu.org/onlinedocs/gccint/Passes.html

Aby zachować wszystkie pliki, które zostają utworzone podczas kompilacji użyj opcji -save-temps. Zostanie zachowany plik po pracy preprocesora (.i), po kompilacji ale przed assmblerem (.S) i przed linkowaniem (.o). Warto pamiętać o opcji -masm=intel, bo inaczej w ASM składnia AT&T wypala oczy.
Można też uzyskać informacje o wszystkich etapach optymalizacji za pomocą opcji -v -Q -fdump-passes -fopt-info-all-optall -fdump-tree-all-all -fdump-rtl-all -fdump-ipa-all -Wl,--verbose. Tych opcji jest w sumie więcej nawet i do tego można wycisnąć z nich jeszcze więcej szczegółów, ale do tego odsyłam do manuala GCC. Uwaga: to potrafi wygenerowac masę plików i łatwo się w tym zgubić.

1 użytkowników online, w tym zalogowanych: 0, gości: 1