26, ciekawostki, Linux - Ksiega Eksperta, Linux - ksiega eksperta, Linux - księga eksperta


Rozdział 26.
Programowanie w języku C


Rick McMullin

W tym rozdziale:

Linux rozprowadzany jest wraz z wieloma programami narzędziowymi wspierającymi tworzenie oprogramowania. Większość z nich przeznaczona jest do współpracy z kompilatorami języka C i C++. Niektóre z tych programów - takie jak debugery (programy służące do wyszukiwania błędów), programy formatujące kod źródłowy czy programy do automatycznego generowania plików nagłówkowych - zostaną omówione w tym rozdziale. Jego celem nie jest nauka programowania w języku C, a tylko przedstawienie zasad używania kompilatora i innych narzędzi przeznaczonych dla programistów.

Język C

C to język programowania przeznaczony do zastosowań ogólnych, stworzony we wczesnej fazie rozwoju systemu UNIX. Pierwsze wersje tego systemu pisane były w asemblerze oraz języku nazywanym B. Język C zaprojektowany został w celu ominięcia niektórych ograniczeń języka B. Od tamtej pory stał się najpopularniejszym językiem używanym w świecie komputerów.

Skąd wynika jego popularność? Oto kilka najważniejszych powodów.

Język C ewoluował dość znacząco w ciągu ostatnich 20 lat. W drugiej połowie lat osiemdziesiątych Amerykański Instytut Standardów (American National Standard Institute) opracował normy obowiązujące w tym języku; standard ten jest dziś znany jako ANSI C. To jeszcze bardziej poprawiło przenośność C. Również w tym okresie do języka C wprowadzono obsługę obiektów, co zaowocowało powstaniem języka C++ (który zostanie omówiony w następnym rozdziale).

Kompilator języka C dla systemu Linux (ang. GNU C compiler, w skrócie GCC) został stworzony w ramach Free Software Foundation i rozprowadzany jest zgodnie z zasadami licencji GNU. Znajdziesz go na dysku CD-ROM dołączonym do tej książki.

Kompilator GNU C

Kompilator GNU C (GCC) jest w pełni funkcjonalnym kompilatorem, spełniającym normy standardu ANSI C. Jeśli potrafisz obsługiwać jakiś inny kompilator języka C, będziesz w stanie nauczyć się obsługi kompilatora gcc w bardzo krótkim czasie. Ten podrozdział opisuje pokrótce używanie tego kompilatora oraz przedstawia najczęściej wykorzystywane opcje.

Uruchamianie GCC

Kompilator GCC wywołuje się podając w wierszu poleceń cały szereg opcji oraz nazw plików. Najprościej składnię jego można zdefiniować następująco:

gcc [opcje] [nawy_plików]

Każdy z plików poddawany jest przetwarzaniu zgodnie z informacjami podanymi za pomocą opcji. Najważniejsze z nich opisane są w następnym podrozdziale.

Opcje kompilatora GCC

Opcji, które mogą zostać przesłane do GCC, jest ponad setka. Większości z nich prawdopodobnie nigdy nie użyjesz, ale niektóre są wręcz niezbędne nawet przy podstawowych zastosowaniach. Wiele opcji może składać się z więcej niż jednego znaku. Z tego powodu każda z nich musi zaczynać się od własnego myślnika, nie można grupować opcji po kilka za jednym myślnikiem, jak ma to miejsce w większości poleceń systemu Linux. Przykładowo, dwa poniższe polecenia nie są równoważne:

gcc -p -g test.c
gcc -pg test.c

Pierwsze mówi kompilatorowi, by skompilował plik test.c, zapisując informacje służące do późniejszego profilowania za pomocą programu prof oraz informacje dla debugera. Drugie polecenie nakazuje skompilowanie tego pliku i zapisanie informacji do profilowania za pomocą programu gprof, nie powoduje natomiast wygenerowania informacji dla debugera.

Kiedy kompilujesz program, nie używając żadnych opcji, w bieżącym katalogu tworzony jest plik wykonywalny (o ile kompilacja zakończy się bez błędów) o nazwie a.out. Jeśli chcesz, by nazwa tworzonego pliku wykonywalnego była inna, powinieneś użyć opcji -o. Przykładowo, aby skompilować program zapisany w pliku licznik.c do pliku wykonywalnego o nazwie licznik, należy wydać polecenie:

gcc -olicznik licznik.c

0x01 graphic

Nazwa pliku wyjściowego musi pojawić się bezpośrednio po opcji -o.

Inne opcje kompilatora decydują o tym, na jakim etapie należy zakończyć proces kompilacji. Opcja -c powoduje zakończenie procesu po utworzeniu pliku pośredniego (domyślnie z rozszerzeniem .o). Jest ona używana dość często, ponieważ umożliwia przyśpieszenie kompilacji złożonych, wieloplikowych programów.

Opcja -S powoduje zakończenie kompilacji po wygenerowaniu plików asemblera (domyślnie z rozszerzeniem .s). Opcja -E powoduje, że kompilator tylko wstępnie przetworzy pliki wejściowe, wykonując zawarte w nich dyrektywy preprocesora. W takim przypadku dane wyjściowe wysyłane są na ekran, a nie do pliku.

Opcje dotyczące optymalizacji

Kompilator GCC stara się utworzyć kod wynikowy w możliwie najkrótszym czasie w taki sposób, by łatwo było znaleźć w nim ewentualne błędy. Oznacza to, że kolejność operacji pozostaje taka sama jak w pliku źródłowym i nie jest dokonywana żadna optymalizacja. Istnieje wiele opcji, dzięki którym możesz nakazać tworzenie mniejszych czy szybszych wersji programów, kosztem czasu ich kompilacji oraz łatwości wyszukiwania błędów. Najczęściej używa się opcji -O oraz -O2.

Opcja -O powoduje zastosowanie podstawowych technik optymalizacyjnych. Owocuje to zwykle powstaniem szybciej działających wersji programów. Opcja -O2 powoduje, że wygenerowany zostanie możliwie krótki oraz szybki kod. Czas kompilacji w tym przypadku jest dłuższy, ale za to program wynikowy działa szybciej.

Poza tymi opcjami istnieje jeszcze wiele opcji niskiego poziomu, których można użyć do dalszego przyspieszania działania programu. Są one jednak bardzo specyficzne i powinieneś używać ich tylko wtedy, gdy dokładnie zdajesz sobie sprawę z tego, co powodują, i jakie mogą być ich konsekwencje. Bardziej szczegółowe informacje o tych opcjach znajdziesz na stronach man (wydaj polecenie man gcc).

Opcje współpracy z debugerem
i programem profilującym

Spośród kilku opcji dotyczących wstawiania dodatkowego kodu służącego do określania szybkości wykonywania programu i ułatwiającego uruchamianie i testowanie, najczęściej używane są dwie: -g oraz -pg.

Opcja -g powoduje dołączenie do pliku wykonywalnego informacji dla debugera gdb, który często okazuje się niezbędny w procesie wyszukiwania błędów. GCC oferuje Ci coś, czego nie daje większość innych kompilatorów: możliwość łącznego użycia opcji -g oraz -O (która powoduje wygenerowanie zoptymalizowanej wersji programu). Jest to bardzo przydatne, szczególnie jeśli chcesz testować produkt jak najbardziej zbliżony do wersji końcowej. Powinieneś jednak zdawać sobie sprawę, że część kodu zostanie przez kompilator nieco zmodyfikowana. Więcej informacji na ten temat znajdziesz w podrozdziale „Wyszukiwanie błędów - debuger gdb”.

Opcja -pg pozwala na dołączenie do programu wykonywalnego dodatkowego kodu, który, po uruchomieniu programu, wygeneruje informacje o czasie wykonania poszczególnych sekcji programu. Informacje te mogą być przeglądane za pomocą programu gprof. Więcej informacji na jego temat znajdziesz w podrozdziale „gprof”.

Wyszukiwanie błędów - debuger gdb

Wraz z Linuxem rozprowadzany jest program gdb, który jest bardzo potężnym debugerem, służącym do wyszukiwania błędów w programach napisanych w językach C i C++. Umożliwia dostęp do struktur danych i pamięci wykorzystywanej przez program podczas jego działania. Oto jego podstawowe zalety:

Program gdb można uruchomić, wydając polecenie gdb. Jeśli Twój system jest prawidłowo skonfigurowany, przywita Cię on informacją podobną do tej:

GDB is free software and you are welcome to distribute copies of it
under certain conditions; type "show copying" to see the conditions.
There is absolutely no warranty for GDB; type "show warranty" for details.
GDB 4.12 (i486-unknown-linux), Copyright 1994 Free Software Foundation, Inc.
(gdb)

Przy uruchamianiu tego programu można również podać różne parametry w wierszu poleceń. Zwykle program ten uruchamia się, podając nazwę pliku wykonywalnego, w którym chcemy szukać błędów:

gdb <nazwa_pliku>

W takim przypadku plik wykonywalny zostanie automatycznie załadowany. Można również uruchomić gdb w ten sposób, by możliwe było oglądanie zawartości pliku ze zrzutem pamięci (ang. core dump) wygenerowanego przez program; można też dołączyć gdb do działającego już procesu. Aby obejrzeć listę dostępnych opcji z ich krótkim opisem, zajrzyj na stronę man lub uruchom gdb z opcją -h.

Kompilowanie kodu przeznaczonego do debugowania

Aby gdb mógł działać poprawnie, do pliku wykonywalnego muszą zostać dołączone przez kompilator informacje o typach i nazwach zmiennych, o mapowaniu kodu na linie programu źródłowego itd., które pozwolą na powiązanie kodu źródłowego i skompilowanego kodu programu.

Aby do tworzonego programu wykonywalnego dołączyć informacje pozwalające na współpracę z debugerem, należy uruchomić kompilator z opcją -g.

Podstawowe polecenia gdb

gdb obsługuje wiele różnych poleceń, od prostych, służących do ładowania pliku itp., aż do bardzo zaawansowanych, pozwalających np. obejrzeć zawartość stosu. Tabela 26.1 zawiera polecenia niezbędne do rozpoczęcia pracy z gdb. Opis pozostałych poleceń znajdziesz na stronach man.

Tabela 26.1. Podstawowe polecenia gdb

Polecenie

Opis

file

Ładuje plik wykonywalny, w którym można będzie szukać błędów.

kill

Kończy działanie aktualnie wykonywanego programu.

list

Wyświetla listę sekcji kodu źródłowego użytego do utworzenia
pliku wykonywalnego.

next

Przechodzi do kolejnego wiersza kodu w bieżącej funkcji,
bez wchodzenia do funkcji podrzędnych.

step

Przechodzi do kolejnego wiersza kodu w bieżącej funkcji,
wchodząc również do funkcji podrzędnych.

run

Powoduje wykonanie bieżącego programu.

quit

Kończy pracę debugera gdb.

watch

Pozwala na sprawdzenie wartości zmiennej po każdej jej zmianie.

break

Ustawia pułapkę w kodzie źródłowym. Pułapka powoduje wstrzymanie
wykonywania programu po dojściu do zadanego punktu.

make

Pozwala na przekompilowanie programu bez konieczności wychodzenia z gdb.

shell

Umożliwia wykonanie polecenia powłoki.

Środowisko gdb obsługuje większość udogodnień znanych z interpreterów poleceń. Można na przykład używać dokańczania poleceń za pomocą klawisza Tab, a jeśli polecenie nie jest jednoznaczne, po ponownym naciśnięciu tego klawisza wyświetlone zostaną wszystkie możliwości. Można również poruszać się po liście wydanych wcześniej poleceń za pomocą klawiszy kursora.

Przykładowa sesja gdb

Ten podrozdział poprowadzi Cię krok po kroku przez przykładową sesję gdb. Program, którym się zajmiemy, będzie nazywał się pozdr, a jego jedynym celem będzie wyświetlenie tekstu prostego pozdrowienia w przód i wstecz.

#include <stdio.h>

main()
{
char moj_tekst[]="Witam Cie";

druk_1(moj_tekst);
druk_2(moj_tekst);
}

void druk_1 (char *tekst)
{
printf ("Tekst normalnie: %s\n",tekst);
}

void druk_2 (char *tekst)
{
char *tekst2;
int rozm, i;
rozm=strlen(tekst);

tekst2=(char *)malloc(rozm+1);
for (i=0; i<rozm; i++)
tekst2[rozm-i]=tekst[i];
tekst2[rozm+1]='\0';
printf ("Tekst wstecz: %s\n",tekst2);
}

Aby skompilować ten program, użyj programu gcc, podając jako parametr nazwę pliku źródłowego. Aby plik wyjściowy nie nazywał się a.out, użyj opcji -o, na przykład tak:

gcc -g -opozdr pozdr.c

Po uruchomieniu program wyświetla następujące informację:

Tekst normalnie: Witam Cie
Tekst wstecz:

Pierwszy wiersz jest w porządku, ale z drugim zdecydowanie jest coś nie tak. Powinien on oczywiście wyglądać następująco:

Tekst wstecz: eiC matiW

Z jakiegoś powodu jednak funkcja druk_2 nie działa prawidłowo. Spróbujmy rozwiązać ten problem za pomocą gdb. Najpierw trzeba go uruchomić:

gdb pozdr

0x01 graphic

Pamiętaj o użyciu opcji -g kompilatora, która spowoduje dodanie do wynikowego programu informacji pozwalających na współpracę z debugerem.

Jeśli nazwa pliku, który należy załadować, nie zostanie podana, można podać ją później, wydając polecenie

(gdb) file pozdr

Spowoduje ono załadowanie pliku wykonywalnego, tak jakby jego nazwa została podana jako argument wywołania.

Spróbujmy teraz uruchomić załadowany program poleceniem run.Na ekranie powinny pojawić się następujące komunikaty:

(gdb) run
Starting program: /root/pozdr
Tekst normalnie: Witam Cie
Tekst wstecz:

Program exited with code 041

Wyniki działania programu nie zmieniły się. Pozostaje pytanie: dlaczego nie działa funkcja druk_2? Aby na nie odpowiedzieć, spróbujmy ustawić pułapkę w wierszu następującym po instrukcji for w funkcji druk_2. W tym celu obejrzyjmy najpierw kod źródłowy, wydając trzykrotnie polecenie list:

(gdb) list
(gdb) list

0x01 graphic

Wciśnięcie klawisza Enter w pustym wierszu powoduje powtórzenie ostatniego polecenia.

(gdb) list

Po pierwszym wprowadzeniu polecenia list na ekranie pojawi się coś takiego:

1 #include <stdio.h>
2
3 main()
4 {
5 char moj_tekst[]="Witam Cie";
6
7 druk_1(moj_tekst);
8 druk_2(moj_tekst);
9 }
10

Wciśnij Enter, a gdb ponownie wykona polecenie list:

11 void druk_1 (char *tekst)
12 {
13 printf ("Tekst normalnie: %s\n",tekst);
14 }
15
16 void druk_2 (char *tekst)
17 {
18 char *tekst2;
19 int rozm, i;
20

A po ponownym wciśnięciu klawisza Enter:

21 rozm=strlen(tekst);

22 tekst2=(char *)malloc(rozm+1);
23 for (i=0; i<rozm; i++)
24 tekst2[rozm-i]=tekst[i];
25 tekst2[rozm+1]='\0';
26 printf ("Tekst wstecz: %s\n",tekst2);
27 }

Po obejrzeniu kodu źródłowego możemy stwierdzić, że pułapkę należy założyć w wierszu o numerze 24.W tym celu trzeba wydać polecenie:

(gdb) break 24

gdb powinien odpowiedzieć w następujący sposób:

Breakpoint 1 at 0x139: file pozdr.c, line 24
(gdb)

Spróbujmy ponownie uruchomić program za pomocą polecenia run. Wygenerowane zostaną następujące komunikaty:

Starting program: /root/pozdr
Tekst normalnie: Witam Cie

Breakpoint 1, druk_2 (string = 0xbfffdc4 "Witam Cie") at pozdr.c : 24
24 tekst2[rozm-i]=tekst[i];

W którym miejscu tkwi błąd, możemy stwierdzić po sprawdzeniu, jaką wartość przyjmuje wyrażenie tekst2[rozm-i]. Można to zrobić za pomocą polecenia watch:

(gdb) watch tekst2[rozm-i]

gdb potwierdzi przyjęcie polecenia krótkim komunikatem:

Watchpoint 2: tekst2[rozm-i]

Wersja debugera dostarczona na dołączonej do tej książki płycie CD-ROM wyświetla nieco inny komunikat - zamiast terminu Watchpoint używane jest określenie Hardware Watchpoint, ale oba te komunikaty mają dokładnie takie samo znaczenie. Możemy teraz prześledzić wykonanie pętli for krok po kroku, używając polecenia

(gdb) next

Po pierwszym przebiegu pętli gdb poinformuje nas, że aktualną wartością obserwowanego wyrażenia tekst2[rozm-i] jest 'W', wyświetlając informacje:

Watchpoint 2, tekst2[rozm-i]
Old value = 0 '\000'
New value = 087 'W'
druk_2(string = 0xbfffdc4 "Witam Cie") at pozdr.c:23
23 for (i=0;i<rozm;i++)

Jest to wartość, której się spodziewaliśmy. Kolejne przejścia pętli również działają bez zarzutu. Po dotarciu do punktu, gdy zmienna i przyjmuje wartość 10, wyrażenie tekst2[rozm-i] przyjmuje wartość 'e', a wartość rozm-i jest równa 1; program doszedł do ostatniego znaku, który należy skopiować do nowej tablicy.

Po kolejnym przebiegu pętli jasne staje się, że nigdy nie następuje przypisanie do zmiennej tekst2[0], będącej pierwszym znakiem tekstu. Ponieważ domyślnie funkcja malloc inicjalizuje pamięć, którą przydziela, wartością NULL, pierwszy znak w przydzielonym obszarze ma kod 0. Kod ten oznacza koniec tekstu, więc nic nie jest wyświetlane. Problem został znaleziony.

Teraz już łatwo jest go naprawić. Trzeba zmienić algorytm tak, aby pierwszy znak kopiowany do łańcucha tekst2 był zapisywany z przesunięciem rozm-1, a nie rozm, ponieważ chociaż długość tekstu Witam Cie wynosi 9, numerowanie rozpoczyna się od 0.

Powyższy program może zostać poprawiony na wiele sposobów, Można na przykład utworzyć oddzielną zmienną określającą długość tekstu, która będzie miała wartość o 1 mniejszą od rzeczywistej długości. Poniżej przedstawiamy program oparty na takim rozwiązaniu:

#include <stdio.h>

main()
{
char moj_tekst[]="Witam Cie";

druk_1(moj_tekst);
druk_2(moj_tekst);
}

void druk_1 (char *tekst)
{
printf ("Tekst normalnie: %s\n",tekst);
}

void druk_2 (char *tekst)
{
char *tekst2;
int rozm, rozm2, i;

rozm=strlen(tekst);
rozm2=rozm-1;
tekst2=(char *)malloc(rozm+1);
for (i=0; i<rozm; i++)
tekst2[rozm2-i]=tekst[i];
tekst2[rozm]='\0';
printf ("Tekst wstecz: %s\n",tekst2);
}

Inne narzędzia dla programistów

W skład dystrybucji Linuxa wchodzą również inne narzędzia mające służyć programistom, które nie zostały jeszcze opisane. Poniżej znaleźć możesz krótkie opisy najpopularniejszych z nich.

xxgdb

xxgdb to interfejs graficzny programu gdb. Dziedziczy więc wszystkie cechy wersji obsługiwanej z wiersza poleceń. Pozwala wykonywać większość podstawowych operacji poprzez wybór odpowiednich przycisków zamiast wydawania poleceń. Graficznie zaznacza punkty, w których zastawione są pułapki.

Uruchomić ten program można, wpisując w oknie terminalu polecenie xxgdb. Można również w wierszu poleceń przekazać wszystkie parametry, które są obsługiwane przez program gdb. Dostępna jest również pewna liczba opcji charakterystycznych tylko dla xxgdb - zostały one zebrane w tabeli 26.2.

Tabela 26.2. Opcje programu xxgdb dostępne w wierszu poleceń

Opcja

Opis

db_name

Pozwala podać nazwę debugera, którego należy użyć; domyślnie jest to gdb

db_prompt

Pozwala określić znak zachęty używany przez debuger; domyślnie - gdb

gdbinit

Określa nazwę pliku inicjalizacyjnego, zawierającego polecenia, które należy wykonywać przy uruchomieniu; domyślnie - .gdbinit

nx

Powoduje, że plik inicjalizacyjny nie będzie przetwarzany

bigicon

Powoduje użycie dużych ikon

Po uruchomieniu xxgdb na ekranie pojawia się jego okno główne - tak jak na rysunku 26.1.

Zawiera ono komunikaty podobne do tych, które wyświetlane są w wersji tekstowej. W środkowej części okna znajdują się przyciski, których wybranie powoduje wywołanie odpowiednich poleceń gdb. Górna część okna zawiera kod źródłowy programu, a dolna - komunikaty generowane przez wykonywany program oraz gdb. Można polecić gdb wyświetlenie wartości jakiejś zmiennej czy wyrażenia przez podświetlenie go w kodzie źródłowym i wciśnięcie przycisku Display w środkowej części okna.

0x01 graphic

W niektórych wersjach xxgdb każda z opisanych wyżej części okna otwiera się w osobnym oknie.

Więcej informacji o programie xxgdb możesz znaleźć na stronach man poświęconych programom gdb i xxgdb.

Rysunek 26.1.

Główne okno programu xxgdb

0x01 graphic

calls

Ten program nie jest zamieszczony na dołączonym do książki CD-ROM-ie. Możesz go znaleźć w archiwum FTP pod adresem ftp://sunsite.inc.edu/pub/Linux/devel/ lang/c/calls.tar.Z. Niektóre starsze dystrybucje Linuxa rozprowadzane na płytach CD-ROM zawierają ten plik. Jeśli uważasz, że program calls będzie Ci potrzebny, powinieneś załadować go z któregoś z węzłów BBS lub FTP albo skopiować z innego dysku CD-ROM. calls uruchamia preprocesor GCC, przetwarzając pliki, których nazwy zostały podane jako argumenty wywołania, a następnie wyświetla drzewo wywołań funkcji w tych plikach.

0x01 graphic

Aby zainstalować program calls w swoim systemie, zaloguj się jako root, a następnie:

  • rozpakuj otrzymane archiwum w katalogu /tmp;

  • wejdź do katalogu calls utworzonego podczas rozpakowywania archiwum;

  • przenieś plik o nazwie calls do katalogu /usr/bin;

  • przenieś plik calls.1 do katalogu /usr/man/man1;

  • usuń katalog /tmp/calls.

Powyższe kroki spowodują zainstalowanie programu calls i poświęconej mu strony man.

Oprócz drzewa wywołań funkcji program calls podaje też (w nawiasach kwadratowych) informacje o pliku, w którym funkcja ta się znajduje, np.:

main [test.c]

Jeśli funkcja nie znajduje się w żadnym z plików wyszczególnionych w wierszu poleceń, wyświetlana jest tylko jej nazwa:

printf

calls informuje również o wywołaniach rekurencyjnych:

sil <<< recursive in silnia.c >>>

oraz funkcjach statycznych:

total [static in calculate.c]

Dla przykładu załóżmy, że za pomocą programu calls chcemy uzyskać informacje o pliku zawierającym następujący program:

#include <stdio.h>

main()
{
char moj_tekst[]="Witam Cie";

druk_1(moj_tekst);
druk_2(moj_tekst);
}

void druk_1 (char *tekst)
{
printf ("Tekst normalnie: %s\n",tekst);
}

void druk_2 (char *tekst)
{
char *tekst2;
int rozm, rozm2, i;

rozm=strlen(tekst);
rozm2=rozm-1;
tekst2=(char *)malloc(rozm+1);
for (i=0; i<rozm; i++)
tekst2[rozm2-i]=tekst[i];
tekst2[rozm]='\0';
printf ("Tekst wstecz: %s\n",tekst2);
}

Po przetworzeniu tego pliku program calls wyświetli następujące informacje:

1 main [pozdr.c]
2 druk_1 [pozdr.c]
3 printf
4 druk_2 [pozdr.c]
5 strlen
6 malloc
7 printf

calls rozpoznaje również wiele opcji podawanych w wierszu poleceń, które pozwalają modyfikować postać informacji wyjściowych oraz rodzaj funkcji, które mają być wyświetlane. Więcej informacji o opcjach programu calls możesz otrzymać, wydając polecenie calls -h i - oczywiście - zaglądając na strony man.

cproto

Program cproto również nie jest zamieszczony na CD-ROM-ie dołączonym do książki. Możesz go otrzymać w każdym archiwum FTP udostępniającym Linuxa. Pozwala on na automatyczne generowanie plików nagłówkowych zawierających deklaracje wszystkich zdefiniowanych w programie funkcji. Dzięki temu można zaoszczędzić sobie ręcznego ich wpisywania.

0x01 graphic

Aby zainstalować program cproto w swoim systemie, zaloguj się jako root, a następnie:

  • rozpakuj otrzymane archiwum w katalogu /tmp;

  • wejdź do katalogu cproto utworzonego podczas rozpakowywania plików;

  • przenieś plik o nazwie cproto do katalogu /usr/bin;

  • przenieś plik cproto.1 do katalogu /usr/man/man1;

  • usuń katalog /tmp/cproto.

Powyższe kroki spowodują zainstalowanie programu cproto i poświęconej mu strony man.

Spróbujmy zastosować program cproto do wygenerowania nagłówków funkcji zdefiniowanych w przykładowym pliku:

#include <stdio.h>

main()
{
char moj_tekst[]="Witam Cie";

druk_1(moj_tekst);
druk_2(moj_tekst);
}

void druk_1 (char *tekst)
{
printf ("Tekst normalnie: %s\n",tekst);
}

void druk_2 (char *tekst)
{
char *tekst2;
int rozm, rozm2, i;

rozm=strlen(tekst);
rozm2=rozm-1;
tekst2=(char *)malloc(rozm+1);
for (i=0; i<rozm; i++)
tekst2[rozm2-i]=tekst[i];
tekst2[rozm]='\0';
printf ("Tekst wstecz: %s\n",tekst2);
}
Program cproto wygeneruje następujące informacje:
/* test.c */
int main(void);
int druk_1(char *tekst);
int druk_2(char *tekst);

Mogą one zostać wykorzystane w pliku nagłówkowym, zawierającym prototypy wszystkich funkcji.

indent

Program indent znajduje się na dołączonej do książki płycie CD-ROM. Program ten formatuje albo drukuje w przyjemnym dla oka układzie kod źródłowy w języku C, zachowując konsekwentny układ wcięć, stały układ nawiasów, nawiasów klamrowych itd. Jego zachowanie można modyfikować, podając odpowiednie opcje w wierszu poleceń - ich opis możesz znaleźć na stronach man lub też po wydaniu polecenia indent -h.

Poniższy przykład pozwoli Ci zorientować się w działaniu tego programu.

Oto kod źródłowy przed sformatowaniem go za pomocą programu indent:

#include <stdio.h>

main() {
char moj_tekst[]="Witam Cie";
druk_1(moj_tekst);
druk_2(moj_tekst);}

void druk_1 (char *tekst)
{
printf ("Tekst normalnie: %s\n",tekst);
}

void druk_2 (char *tekst) {
char *tekst2;
int rozm, rozm2, i;

rozm=strlen(tekst);
rozm2=rozm-1;
tekst2=(char *)malloc(rozm+1);
for (i=0; i<rozm; i++)
tekst2[rozm2-i]=tekst[i];
tekst2[rozm]='\0';
printf ("Tekst wstecz: %s\n",tekst2);
}

A to ten sam kod po sformatowaniu:

#include <stdio.h>

main ()
{
char moj_tekst[]="Witam Cie";
druk_1(moj_tekst);
druk_2(moj_tekst);
}

void druk_1 (char *tekst)
{
printf ("Tekst normalnie: %s\n",tekst);
}

void druk_2 (char *tekst)
{
char *tekst2;
int rozm, rozm2, i;

rozm=strlen(tekst);
rozm2=rozm-1;
tekst2=(char *)malloc(rozm+1);
for (i=0; i<rozm; i++)
tekst2[rozm2-i]=tekst[i];
tekst2[rozm]='\0';
printf ("Tekst wstecz: %s\n",tekst2);
}

Program indent nie zmienia kodu w sensie składniowym - kompilator zrozumie go dokładnie w ten sam sposób. Zmienia tylko wygląd kodu źródłowego, dzięki czemu staje się on bardziej czytelny, co zawsze jest godne uwagi.

gprof

Program gprof instalowany jest w katalogu /usr/bin. Pozwala on na profilowanie tworzonych programów, tzn. ustalanie, na czym spędzają one najwięcej czasu.

gprof podaje informacje o tym, ile razy wywołana została każda funkcja, oraz ile procent ogólnego czasu wykonania programu zajęła. Dzięki temu można łatwo stwierdzić, która część kodu programu wymaga usprawnienia.

Aby można było używać programu gprof, tworzony program musi zostać skompilowany z załączoną opcją -pg kompilatora. Dołączony do programu kod spowoduje utworzenie pliku o nazwie gmon.out. Ten plik jest następnie przetwarzany przez program gprof, który przedstawia zawarte w nim informacje w czytelny sposób.

Po uruchomieniu testowanego programu (i utworzeniu pliku gmon.out) należy uruchomić program gprof podając nazwę pliku programu jako parametr:

gprof <nazwa_programu>

0x01 graphic

Dane wyświetlane przez program gprof są dość sporych rozmiarów, dlatego warto skierować je do pliku.

f2c oraz p2c

Programy f2c i p2c służą do konwersji kodu źródłowego - f2c zamienia kod źródłowy w języku FORTRAN na kod w języku C, natomiast p2c - kod napisany w Pascalu na C. Oba te programy instalowane są automatycznie przy instalacji kompilatora GCC.

Jeśli masz kod źródłowy programu napisanego w języku FORTRAN albo Pascal, a chcesz przepisać go w języku C, programy te będą Ci bardzo pomocne. Potrafią one wygenerować kod w języku C, który może być zwykle skompilowany za pomocą kompilatora gcc bez interwencji programisty.

Przy konwertowaniu niewielkich, prostych programów, kod wynikowy powinien nadawać się bezpośrednio do skompilowania. W przypadku programów bardziej skomplikowanych, składających się z kilku plików, nie obejdzie się bez podania dodatkowych opcji.

Aby przetłumaczyć na C program w języku FORTRAN, powinieneś wydać polecenie

f2c pr_fortran.f

0x01 graphic

f2c wymaga, aby plik zawierający kod źródłowy konwertowanego programu posiadał rozszerzenie .f albo .F.

Konwersji programu w Pascalu dokonać możesz poprzez wydanie polecenia:

p2c pr_pascal.pas

Programy p2c i f2c tworzą plik zawierający kod źródłowy w języku C, o takiej samej nazwie, jak plik zawierający konwertowany program, ale z rozszerzeniem .c zamiast .f czy .pas.

Więcej informacji o specyficznych opcjach dostępnych w tych programach znajdziesz na stronach man.

Podsumowanie

W rozdziale tym omówiliśmy pokrótce zasady użycia kompilatora GNU C, wraz z częściej używanymi opcjami. Przedstawiliśmy również podstawowe zasady posługiwania się programami gdb i xxgdb oraz wspomnieliśmy o kilku innych narzędziach ułatwiających pracę programisty.

0x01 graphic

Jeśli będziesz pisał programy w języku C, czas, który przeznaczysz na naukę obsługi gdb i innych programów narzędziowych zwróci się wielokrotnie podczas wyszukiwania usterek w programach.

W następnym rozdziale omówimy podobne tematy, skupiając się jednak na języku C++. Jeśli chcesz, możesz przejść do innych rozdziałów.

Rozdział 28. „Perl” dotyczy języka Perl, doskonale nadającego się do tworzenia skryptów.

Tcl i Tk, języki używane głównie do tworzenia makropoleceń, przedstawione są w rozdziale 29. „Podstawy języków Tcl i Tk”.

Inne kompilatory dostępne w systemie Linux opisane są w rozdziale 30. „Inne kompilatory”.

O języku Smalltalk przeczytać możesz w rozdziale 31. „Smalltalk/X”.

444 Część V Linux dla programistów

444 E:\Moje dokumenty\HELION\Linux Unleashed\Indeks\26.DOC

E:\Moje dokumenty\HELION\Linux Unleashed\Indeks\26.DOC 445

Rozdzia³ 26. Programowanie w języku C 445



Wyszukiwarka

Podobne podstrony:
43, ciekawostki, Linux - Ksiega Eksperta, Linux - ksiega eksperta, Linux - księga eksperta
34, ciekawostki, Linux - Ksiega Eksperta, Linux - ksiega eksperta, Linux - księga eksperta
58, ciekawostki, Linux - Ksiega Eksperta, Linux - ksiega eksperta, Linux - księga eksperta
08, ciekawostki, Linux - Ksiega Eksperta, Linux - ksiega eksperta, Linux - księga eksperta
10, ciekawostki, Linux - Ksiega Eksperta, Linux - ksiega eksperta, Linux - księga eksperta
57, ciekawostki, Linux - Ksiega Eksperta, Linux - ksiega eksperta, Linux - księga eksperta
29, ciekawostki, Linux - Ksiega Eksperta, Linux - ksiega eksperta, Linux - księga eksperta
46, ciekawostki, Linux - Ksiega Eksperta, Linux - ksiega eksperta, Linux - księga eksperta
60, ciekawostki, Linux - Ksiega Eksperta, Linux - ksiega eksperta, Linux - księga eksperta
36, ciekawostki, Linux - Ksiega Eksperta, Linux - ksiega eksperta, Linux - księga eksperta
49, ciekawostki, Linux - Ksiega Eksperta, Linux - ksiega eksperta, Linux - księga eksperta
62, ciekawostki, Linux - Ksiega Eksperta, Linux - ksiega eksperta, Linux - księga eksperta
D, ciekawostki, Linux - Ksiega Eksperta, Linux - ksiega eksperta, Linux - księga eksperta
55, ciekawostki, Linux - Ksiega Eksperta, Linux - ksiega eksperta, Linux - księga eksperta
28, ciekawostki, Linux - Ksiega Eksperta, Linux - ksiega eksperta, Linux - księga eksperta
61, ciekawostki, Linux - Ksiega Eksperta, Linux - ksiega eksperta, Linux - księga eksperta
42, ciekawostki, Linux - Ksiega Eksperta, Linux - ksiega eksperta, Linux - księga eksperta
03, ciekawostki, Linux - Ksiega Eksperta, Linux - ksiega eksperta, Linux - księga eksperta
31, ciekawostki, Linux - Ksiega Eksperta, Linux - ksiega eksperta, Linux - księga eksperta

więcej podobnych podstron