Spis treści

Pierwsze, tradycyjne „Hello world!”

„Hello World!” z użyciem biblioteki standardowej C

Używając biblioteki standardowej C, przykładowy program „Hello World!” możemy po prostu przepisać z podręcznika. Oto kod, dla przypomnienia:

#include <stdio.h>

int main(void)
{
  printf("Hello World!\n");
  return 0;
}

Kod źródłowy można przepisać do edytora tekstowego i zapisać jako helloworld.c (skopiowanie nie zadziała, bo dla potrzeb strony wcięcia kodu zrobione są niełamiącymi spacjami). Aby go skompilować, otwieramy okno konsoli (z menu Ambienta, albo używając skrótu klawiszowego rcommand + n) i zmieniamy katalog bieżący na ten zawierający kod źródłowy. Uruchamiamy kompilator:

gcc -o helloworld helloworld.c

Kompilator stworzy plik wykonywalny helloworld, na moim systemie posiada on długość 10 340 bajtów. Warto zauważyć, że w MorphOS-ie rozszerzenia pilków nie są istotne więc dodanie .exe na końcu nazwy nie jest konieczne, chociaż możliwe. Tradycyjnie pliki wykonywalne w MorphOS-ie nie mają żadnego rozszerzenia nazwy. Opcja kompilatora −o specyfikuje nazwę tworzonego pliku wykonywalnego. Jeżeli opcja ta nie zostanie użyta, plik wynikowy zostanie nazwany a.out (z powodów historycznych).

Jak to opisano w rozdziale o SDK, biblioteka standardowa C jest dostarczana przez ixemul.library. Można to łatwo sprawdzić, śledząc aktywność dyskową programu za pomocą narzędzia Snoopium:


Śledzenie aktywności dyskowej programu w Snoopium.

Jak widać, program otwiera również inne biblioteki, nawet związane z komunikacją sieciową i stosem TCP/IP. Wygląda to na lekką przesadę, jak na taki prosty program. Dzieje się tak dlatego, że biblioteka ixemul.library tworzy programowi kompletne środowisko uniksopodobne, które w tym przypadku do niczego w gruncie rzeczy nie jest potrzebne. Dlatego zaleca się używanie statycznie linkowanej biblioteki libnix zamiast ixemul.library. W tym celu dodajemy do wywołania kompilatora opcję −noixemul, będzie ono teraz wyglądało następująco:

gcc -noixemul -o helloworld helloworld.c

Wygenerowany plik wykonywalny jest teraz znacznie większy (na moim systemie 30 964 bajty), co potwierdza fakt, że tym razem użyte funkcje biblioteki standardowej zostały pobrane z libnix-a i statycznie zlinkowane z programem, zwiększając tym samym jego rozmiar. Każdy podręcznik języka C mówi o tym, że printf() jest jedną z najkosztowniejszych (w sensie rozmiaru kodu) funkcji standardowego wejścia/wyjścia, co właśnie potwierdziliśmy eksperymentalnie... Z drugiej strony aktywność dyskowa programu została zredukowana do trzech linijek w Snoopium, nasz program nie ładuje żadnych dodatkowych zasobów.

„Hello World!” z użyciem natywnego API systemu

MorphOS API (Application Programmer Interface) zawiera kompletną obsługę wejścia/wyjścia dla plików i konsoli tekstowej. W rzeczywistości funkcje z bibliotek standardowych C i C++ są mniej lub bardziej skomplikowanymi nakładkami na funkcje natywne. Bezpośrednie użycie funkcji natywnych ma następujące zalety:

Ceną jaką za to płacimy jest utracenie przenośności kodu (z wyjątkiem – do pewnego stopnia – portów dla AmigaOS i AROS-a).

Przykład „Hello World!” z użyciem natywnego API MorphOS-a wygląda jak następuje:

#include <proto/dos.h>

int main(void)
{
  Printf("Hello World!\n");
  return 0;
}

Dołączany plik nagłówkowy proto/dos.h zawiera wszystko, co potrzebne do użycia biblioteki współdzielonej dos.library, zawierającej funkcję Printf(). Funkcja ta działa tak samo jak standardowy printf() z kilkoma nieistotnymi zazwyczaj różnicami. Kod kompilujemy poleceniem:

gcc -noixemul -o helloworld helloworld.c

Polecenie jest takie samo jak dla programu używającego libnix-a i standardowej funkcji printf(), niemniej funkcja ta nie jest użyta, więc nie jest linkowana z programem. Dzięki temu rozmiar pliku wykonywalnego zmniejsza się do 13 500 bajtów.

Dlaczego wciąż potrzebujemy libnix-a, mimo, że nie używamy w kodzie funkcji z biblioteki standardowej C? Czy nie można tego przykładu skompilować z opcją −nostdlib? Niestety nie, bowiem libnix zapewnia tu nam nie tylko funkcje standardowe, ale także kod startowy programu. Program bez takiego kodu zostanie poprawnie wywołany z konsoli, ale zawiesi się, gdy uruchomimy go z poziomu Ambienta. Kod startowy zajmuje się również automatycznym otwieraniem i zamykaniem systemowych bibliotek współdzielonych. Całkowite pozbycie się libnix-a jest zatem możliwe, ale wymaga napisania własnego kodu startowego oraz ręcznej obsługi bibliotek.

Uwaga: całkowita eliminacja biblioteki standardowej jest często wykonywana przy budowaniu komponentów systemu: bibliotek współdzielonych, czy klas publicznych MUI i Reggae. Można to zrobić również dla zwykłego programu aby uczynić go krótszym, szczególnie, jeśli program jest mały. Dla większych projektów zysk na rozmiarze pliku wykonywalnego uzyskany przez napisanie własnego kodu startowego jest zazwyczaj niewart włożonej dodatkowej pracy.