Alimpana rauta joka sekin muodostuu useasta kerroksesta, rautaa ohjelmoidaan konekielellä. Raudan ja sovellusten välillä käyttöjärjestlemä. Käyttöjärjestelmän lisäksi koneissa systeemiohjelmistoa kuten kääntäjät, editorit, komentotulkki, ikkunointiympäristö.
Käyttöjärjestelmällä on kaksi tehtävää:
Esimerkiksi levylle talletetut tiedot ovat vain joukkoja bittejä, joista tieto koodataan magnetoimalla levypintaa. Käyttöjärjestelmä tarjoaa käyttäjälle näkymän missä levylle talletettava tieto organisoidaan tiedostojen ja hakemistojen avulla.
Sovellus käsittelee tiedostoja systeemikutsujen (esim. open, read, write, close) tai kirjastorutiinien (esim. fopen, fgets, fputs, fwrite, wread, fclose) avulla. Sovelluksen käytössä ovat siis tiedostojen tasolla toimivat operaatiot, esim. lue dataa tiedostosta.
Käyttöjärjestelmä huolehtii laitteiden käyttöön liittyvistä yksityiskohdista, eli esim. mihin kohtaan levyä tietyn tiedoston bitit ovat tallentuneet. Sovellusohjelman kannalta ei ole edes väliä minkä valmistajan laitteesta on kyse.
Käyttöjärjestelmä siis tarjoaa rajapinnan, jonka päälle on huomattavasti helpompi rakentaa sovelluksia kuin suoraan raudan päälle.
Systeemikutsu (esim. tiedoston lukeminen) saattaa aiheuttaa sen, että kutsuva ohjelma (tai prosessi niinkuin suorituksessa olevaa ohjelmaa kutsutaan) jää odottamaan kutsun aiheuttaman toimenpiteen valmistumista. Tässä tapauksessa kutsun tehnyt ohjelma siirtyy pois suorituksesta ja suoritukseen valitaan joku toinen ohjelma. Kun systeemikutsun toimenpide on suoritettuna, voidaan kutsun tehnyt ohjelma taas tuoda jossain vaiheessa suoritukseen.
Unixissa systeemikutsuja on noin 100-200 kpl. Koska Unixeista on useita versioita (mm. Linux) on olemassa standardoitu POSIX-rajapinta, jota kaikki UNIX:it pyrkivät noudattamaan. Näin eri UNIX:ien versioista on saatu yhteensopivia.
Seuraavassa joitakin systeemikutsuja:
Ohjelmoija ei käytä välttämättä suoraan systeemikutsuja. Esim. Javassa ohjelmoija käyttää KJ:n tarjoamia palveluja epäsuoraan Java API:n kautta. Samoin esim. C ja C++ tarjoavat ohjelmoijalle korkeamman tason kirjastorutiineja. Kirjastorutiinien toteutus käyttää systeemikutsuja.
Tutustumme kurssin aikana Linuxin tarjoamaan systeemikutsurajapintaan sekä GNU C -kirjastoon. Koska C on Linuxien ja UNIX:ien äidinkieli, ohjelmoimme kurssilla käyttäen C-kieltä. Koska C on C++:n osajoukko, ovat kaikki palvelut suoraan C++-ohjelmien käytössä.
Linuxin käyttö ohjelmointialustana on kasvussa. Linux on tulossa myös mobiilimaailmaan. Motorolan kännykät toimivat jo suurimmaksi osaksi Linux-alustalla toimivia. Myös Nokia on siirtymässä Linuxin käyttöön, N770 ja N800 -mallien myötä
Koneilla pyörii yhtäaikaisesti monta ohjelmaa, eli käytössä on moniajo. Prosessoreja on usein vain yksi, eli prosessoriaikaa on jaettava ohjelmien kesken. Nykyään on tietysti olemassa moniytimisiä prosessoreja, mutta ongelma on sama, ohjelmia voi olla käynnistettynä enemmän kun koneessa on suoritusyksiköitä.
Koneen muistista pitää varata tilaa jokaiselle suoritettavalle ohjelmalle. Usean käyttäjän ympäristössä on huolehdittava suojauksesta. Vain omistaja saa pääsee käsiksi omiin tiedostoihinsa. On myös huolehdittava siitä, että yksittäinen ohjelma ei pääse sotkemaan muita koneella pyöriviä ohjelmia.
Resursseja jaettava tehokkaasti. Esim. tiedon lukeminen kiintolevyltä on tietokoneen mittakaavassa hidasta. Jos jokin ohjelma tekee levyhaun, ei kannata tuhlata CPU-aikaa tiedon odottamiseen. Odotusaikana kannattaa suorittaa CPU:lla jotain muuta ohjelmaa.
Resurssien jakelussa oltava reilu. Jos koneella yhtä aikaa useita sovelluksia, ei mitään saa laiminlyödä, vaan suoritusaikaa on jaettava kaikille. Jos useita suoritettavia ohjelmia (esim. mp3-soitin, ja www-selain), on kaikille annettava CPU-aikaa riittävän usein. Suorituksessa olevan ohjelman vaihtaminen vie kuitenkin jonkin verran CPU:aikaa. Eli mitä useammin suoritettavaa ohjelmaa vaihdetaan, sitä enemmän CPU-aikaa menee hukkaan. Toisaalta suorituksessa olevaa ohjelmaa on pakko vaihtaa usein, jotta käyttö on järkevää: esim. mp3-soittimen on saatava niin usein suoritusvuoro, että musiikki kuulostaa katkeamattomalta.
Muistinhallinta toteutetaan yleensä käyttäen virtuaalimuistia. Ohjelmat luulevat toimivansa kokonaan omassa, yhtenäisessä muistialueessaan. Yksittäinen ohjelma ei näe muiden ohjelmien muistialuetta (ellei näin haluta tapahtuvan). Käyttöjärjestelmä sijoittelee ohjelmien muistialueet eri puolille koneen fyysistä muistia. Voi olla, että osa muistialueista sijoitetaan tilapäisesti levylle ns. swap-alueelle. Kaikki tämä tapahtuu koneen käyttäjän, ohjelman ja sovellusohjelmoijan kannalta huomaamattomasti.
Ohjelmoijan kannalta paras editori on Emacs. Ohjeita emacsin käyttöön:
Suoritettavalle ohjelmalle voidaan antaa jo käännösvaiheessa joku järkevämpi nimi antamalla komento gcc testi.c -o testiohj. Näin syntyy suoritettava ohjelmatiedosto nimeltä testiohj.
Joskus käännöksessä tarvitaan parametrejä. Esim. matematiikkakirjastoa käyttävä ohjelma käännetään antamalla parametri -lm: gcc testi.c -o testiohj -lm
Kääntäjä antaa varoituksia (warning) epäilyttävistä koodiriveistä käyttämällä parametria -Wall: gcc testi.c -o testiohj -Wall. Varoitusten mukaan ottaminen käännökseen on järkevää.
Jos kaikki koodi ei ole yhdessä tiedostossa tai käännösparametreja on paljon, kannattaa käyttää make:a ja Makefile:ä. Lisää make-työkalusta.
Debuggerin käyttö on isommissa ohjelmointiprojekteissa lähes välttämätöntä. Ohjeita GNU-debuggerin eli gdb:n käyttöön:
Jos etsitään tietoa esimerkiksi funktiosta open, on oltava tarkkana. Jos annetana käsky man open tulostuu seuraava:
OPEN(1) Linux 1.x OPEN(1) NAME open - start a program on a new virtual terminal (VT). SYNOPSIS open [-c vtnumber] [-s] [-u] [-l] [-v] [--] command command_options DESCRIPTION open will find the first available VT, and run on it the given command with the given command options, standard input, output and error are directed to that terminal. The current search path ($PATH) is used to find the requested command. If no command is specified then the envi- ronment variable $SHELL is used.
OPEN(2) System calls OPEN(2) NAME open, creat - open and possibly create a file or device SYNOPSIS #include < sys/types.h> #include < sys/stat.h> #include < fcntl.h> int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode); int creat(const char *pathname, mode_t mode); DESCRIPTION The open() system call is used to convert a pathname into a file descriptor (a small, non-negative integer for use in subsequent I/O as with read, write, etc.). When the call is successful, the file descriptor returned will be the lowest file descriptor not currently open for the process. This call creates a new open file, not shared with any other process. (But shared open files may arise via the fork(2) system call.) The new file descriptor is set to remain open
PRINTF(3) Linux Programmer's Manual PRINTF(3) NAME printf, fprintf, sprintf, snprintf, vprintf, vfprintf, vsprintf, vsnprintf - formatted output conversion SYNOPSIS #include < stdio.h> int printf(const char *format, ...); int fprintf(FILE *stream, const char *format, ...); int sprintf(char *str, const char *format, ...); int snprintf(char *str, size_t size, const char *format, ...); #include < stdarg.h> int vprintf(const char *format, va_list ap); int vfprintf(FILE *stream, const char *format, va_list ap); int vsprintf(char *str, const char *format, va_list ap); int vsnprintf(char *str, size_t size, const char *format, va_list ap); DESCRIPTION The functions in the printf family produce output according to a format
Toinen erinomainen tietolähde on GNU C -kirjaston online-dokumentaatio. GNU-dokumentaatio on paikoin man-sivuja helppolukuisempaa ja sisältää joitakin koodiesimerkkejä. Myös C/C++ Refefence sivuilla hyvää materiaalia C standardifunktioista.
Linux-alustalla ohjelmoinnista on olemassa suuri määrä kirjoja. Tämän kurssin materiaaliin ovat vaikuttaneet ainakin seuraavat kirjat: