1. JOHDANTO C-kieli on perustana useille muille ohjelmointikielille. Esimerkiksi C++-kieli on kehitetty C- kielestä, Java- ja C#-kielen syntaksin perustana on toiminut C-kieli ja useat muutkin ohjelmointikielet ovat saaneet vaikutteita C-kielestä. C-kieli on nykyäänkin yhä edelleen se perusohjelmointikieli, joka kuuluu insinöörien perustyökaluihin. Voidaan leikkisästi sanoa, että C-kieli on insinöörin mopo. 1.1 Historia Dennis Ritchie kehitti C-kielen 1970-luvun alussa ja toteutti siitä ensimmäisen version vuonna 1972. Dennis Ritchie työskenteli tuolloin AT&T:n Bellin laboratoriossa Yhdysvalloissa. C- kielen syntyyn johtanut prosessi alkoi BCPL-kielestä (Basic Combined Programming Language), jonka kehittäjä oli Martin Richards. Ken Thompson kehitti BCPL-kielestä B-kielen, jonka puolestaan johti C-kielen syntymiseen. Kuvassa 1-1 on esitetty kielet joihin C- ja C++ - kieli perustuvat. BCPL Algol68 Simula67 Ada CLU C C++ Kuva 1-1. C- ja C++ kielien perustana olevat kielet. 1.2 Standardointi Ohjelmien ja sovellusten siirrettävyys on tärkeä tekijä ohjelmointikielen käytön kannalta. Mitä tarkemmin ohjelmointikieli on standardoitu, sitä paremmin sen kääntäjät ovat yhteensopivia eri laite- ja käyttöjärjestelmäympäristöissä. C-kielen kehittämisen jälkeen kului melkein 20 vuotta ennen, kuin ensimmäinen virallinen C- kielen standardi saatiin aikaiseksi. Näiden vajaan 20 vuoden aikana C-kielestä oli toki olemassa ns. de facto standardi. Tämän määritteli ensimmäisenä Brian Kernighan ja Dennis Ritchie kirjassa The C Programming Language (Englewood Cliffs, N.J.: Prentice-Hall, 1978). Ensimmäistä virallista standardia varten perustettiin komitea kesällä 1983, jonka tehtävänä oli luoda ANSI (American National Standards Institute), joka määrittelisi C-kielen. Standardointiprosessiin kului aikaa 6 vuotta. Ensimmäinen ANSI C standardi valmistui joulukuussa vuonna 1989. Tämä sai myös ISO:n (International Standarda Organization) hyväksynnän. Tämän jälkeen standardia on tyypillisesti nimitetty ANSI/ISO C standardiksi. Vuonna 1995 standardia täydennettiin lisäpiirteillä ja mukaan liitettiin uusia kirjastofunktioita. Vuoden 1989 standardi täydennettynä vuoden 1995 lisäpiirteinä toimi C++-kielen kehittämisen perustana. 8
Vuonna 1999 valmistui viimeisin C-kielen standardi, jota on kutsuttu C99:ksi. Vuoden 1989 standardi voi selvyyden vuoksi kutsua C89:ksi. C99 standardoinnin yhteydessä säilytettiin lähes kaikki C89:n piirteet, joten C99 sisältään C89:sän ja joukon uusia piirteitä sekä ominaisuuksia. 1.3 Sijoittuminen muiden ohjelmointikielten joukkoon C-kieli on ns. välitason ohjelmointikieli. Tämä ei tarkoita sitä, että C-kieli olisi tehottomampaa, vaikeampaa oppia tai kehittää ohjelmia, kuin korkeamman tason ohjelmointikielien ollessa kyseessä. Pikemminkin tämä tarkoittaa sitä, että C-kielessä on mukana korkeammantason ohjelmointikielten parhaita elementtejä mukaan lukien hallintarakenteet yhdistettynä assembler-kielestä tutun joustavuuden kanssa. Kuvassa 1-2 on esitetty C-kielen sijoittuminen joihinkin tunnettuihin ohjelmointikieliin nähden. Middle level: Kuva 1-2. C-kielen sijoittuminen joidenkin tunnettujen ohjelmointikielien suhteen. C-kielen syntaksi sallii yksittäisten bittien käsittelemisen, tavuja käsittelemisen, sanojen käsittelemisen sekä osoitteiden käsittelemisen. C-kielellä voidaan siis käsitellä tietokoneen tiedonkäsittelyn peruselementtejä, jolloin kieli soveltuu hyvin myös laiteläheiseen ohjelmointiin (Esim. sulautetut järjestelmät). Tästä huolimatta C-kielellä kirjoitetut ohjelmat ovat hyvin siirrettävissä olevia laite- ja käyttöjärjestelmäympäristöstä toiseen. Siirrettävyydellä tarkoitetaan yhteensopivuutta (Portability), jolloin ohjelmat on helppo muuttaa toimimaan erilaisissa ympäristöissä. Korkeantason ohjelmointikielet tukevat erilaisia tietotyyppejä (Data types). Yleiset tietotyypit ovat kokonaisluku- (Integer), merkki- (Character) ja liukulukutyyppi (Floating-point). Vaikka C- kielessä on useita ns. sisään rakennettuja tyyppejä, niin tästä huolimatta kieli ei ole kovin vahvasti tyypitetty. C-kieli mahdollistaa lähes kaiken tyyppiset tyyppimuunnokset. C-kielessä on myös mahdollista tehdä ns. johdettuja tyyppejä, jo olemassa olevista tyypeistä. C-kieli ei ole kovin voimakkaasti tyypitetty ohjelmointikieli. Tämä tarkoittaa sitä, että C-kielessä lähes kaiken tyyppiset tyyppimuunnokset (Type cast) ovat mahdollisia. 9
C-kielen yksi keskeinen piirre on se, että sen syntaksi sisältää hyvin rajatun määrän käskyjä eli varattuja sanoja. Standardi C89 sisälsi vain 32 varattua sanaa. Kuvassa 1-3 on esitetty C- kielen varatut sanat. auto double int struct break else long switch case enum register typedef char extern return union const float short unsigned continue for signed void default goto sizeof volatile do if static while Kuva 1-3. C-kielen varatut (Määritetty C89). Standardissa C99 uusia varattuja sanoja tuli lisää vain 5 kappaletta. Kuvassa 1-4 on esitetty nämä sanat. _Bool _Imaginary restrict _Complex inline Kuva 1-4. C-kielen standardiin C99 lisätyt varatut sanat. 1.4 C-kielinen ohjelma C-kieli tukee rakenteellista ohjelmointia. Rakenteellisen ohjelmoinnin perusteisiin kuuluu eri tyyppisten lohkojen käyttö kuten toisto ja valintarakenteet. Toistorakenteita (Silmukka, Luuppi) ovat esimerkiksi seuraavat: for while do-while Toinen rakenteellisen ohjelmoinnin perustekniikka on aliohjelmien käyttö. Aliohjelmien avulla ohjelmistosta saadaan modulaarinen rakenteeltaan sijoittamalla toiminnot omiin aliohjelmiinsa. Aliohjelmien avulla voidaan samaa ohjelman osaa käyttää monesta ohjelman kohdasta kutsumalla ao. aliohjelmaa. Lisäksi aliohjelmat muodostavat oman ns. näkyvyysalueensa, jossa voidaan määritellä esim. muuttujia, jotka eivät näy eli ole käytettävissä aliohjelman ulkopuolella. Kolmas rakenteellisuutta tukeva ominaisuus C- kielessä on se, että eri käännösyksiköitä (lähdetekstitiedostot) voidaan kääntää erikseen ja sitten yhdistää linkittämällä nämä jälkeenpäin yhdeksi ohjelmistoksi. 10
1.4.1 Lähdeteksti C-kielinen ohjelma koostuu erilaisista lohkoista. C-kieliseen ohjelmaan kuuluu aina yksi pääohjelma. Tämä pääohjelma on nimeltään main. Lisäksi ohjelmaan voi kuulua yksi tai useampi aliohjelma (Function) sekä tarvittava määrä ns. globaaleja määrityksiä ja tietorakenteita. Globaalit määritykset ja tietorakenteet ovat määrityksiä, jotka sijaitsevat pääohjelman ja aliohjelmien ulkopuolella. Kuvassa 1-5 on yksinkertaisen, mutta täydellinen C-kielisen ohjelman lähdekoodi (Tätä voi myös nimittää C-kieliseksi ohjelmaksi kunhan muistaa, että tästä lähdetekstistä käännetään sitten lopullinen konekielinen ohjelma koodi, joka on vasta suorituskelpoinen.). #include <stdio.h> void main ( ) { printf ("C-kieli on insinoorin mopo!") ; } Kuva 1-5. C-kielisen ohjelman ohjelmakoodi. C-kielessä itsessään ei ole komentoja joilla voitaisiin suorittaa esim. input/output (I/O) operaatioita, monimutkaisia matemaattisia laskutoimituksia kuten vaikka logaritmin laskemista tai vaikka merkkien käsittelyrutiineja. Tästä johtuen C-kieleen on liitetty joukko ulkopuolisia funktioita em. kaltaisten operaatioiden toteuttamiseksi. Nämä funktiot on kirjastoitu erillisiin tiedostoihin aihealueittain, jotka sitten yhdessä muodostavat C-kielen standardikirjaston (C s standard library). Kuvan 1-5 esimerkissä on käytetty yhtä standardikirjaston funktiota printf, jota käytetään esim. tulostettaessa jotakin näytölle. Kirjastot täytyy ottaa eli ns. inkluudata mukaan ohjelmakoodiin. Tämä tapahtuu komennolla #include <stdio.h>, tässä stdio.h niminen standardikirjaston tiedosto otetaan mukaan ohjelmaan. stdio.h sisältää standardien tulostus- ja syöttöfunktioiden määrittelyt. Standardikirjaston lisäksi käytettävään ohjelmistokehitysympäristöön voi kuulua standardoimattomia funktioita, joita voi myös käyttää. Esimerkiksi Borlandin ohjelmistojen kehitysympäristöissä on funktio clrscr(), joka tyhjentää kuvaruudun. 1.4.2 Ohjelman kehittäminen C-kielellä kirjoitettavan ohjelman kehittämisessä (Kts. kuva 1-6) on seuraavat päävaiheet: 1. Lähdetekstitiedoston (-jen) kirjoittaminen 2. Lähdetekstitiedoston (-jen) kääntäminen objektitiedostoiksi 3. Lähdetekstitiedoston (-jen) ja tarvittavien kirjastofunktioiden linkittäminen yhdeksi suoritettavaksi ohjelmakokonaisuudeksi. Kuvassa 1-6 on esitetty C-kielisen ohjelman kehittämisen päävaiheet. 11
LÄHDEKOODI Ohjelmal.C Sisällytys (Esikääntäjä) Otsikko.H KÄÄNNÖS Ohjelma.OBJ + Käännetyt moduulit LINKITYS Ohjelma.EXE KIINTOLEVY Kuva 1-6. C-kielisen ohjelman kehittämisen päävaiheet. Linkitysvaiheessa muodostetaan ohjelmoijan itse kirjoittamasta lähdekoodista, joka on käännetty konekielelle (Machine code) tietokoneen ymmärtämään muotoon eli objektikoodiksi (Konekielistä koodia tietokone pystyy lukemaan ja suorittamaan.) ja kirjastoissa valmiiksi olevista lähdekoodeista suorituskelpoinen ohjelmakokonaisuus. Kirjastoissa olevat valmiit funktiot ovat ns. uudelleen sijoitettavaa tyyppiä (Relocatable). Tämä tarkoittaa sitä, että funktioiden koodien käskyille ei ole määrätty etukäteen ehdottomia (Absolute) osoitteita, vaan koodin käskyt saavat suhteelliset osoitteet. Näiden suhteellisten osoitteiden avulla kirjastofunktioiden koodit saavat linkitysvaiheessa vasta ns. oikeat ohjelmoijan kirjoittamaan koodiin sopivat osoitteet. 1.4.3 Ohjelman suorittaminen On olemassa kaksi pääasiallista tapaa suorittaa (Execute) eli ajaa ohjelma. Ohjelma voidaan kääntää ennen sen suorittamista tai ohjelmaa voidaan tulkata sen suorittamisen aikana. C- kieli on tarkoitettu käännettäväksi ennen sen suorittamista. Java esimerkiksi on tehty tulkattavaksi kieleksi. Pääsääntöisesti etukäteen käännetty ohjelmakoodin suorittaminen on nopeampaa, kuin koodin jota tulkataan ajonaikana. Tämä johtuu tulkkaukseen kuluvasta ns. ylimääräisestä ajasta (Overhead). 12
Ohjelman suorittamisessa on seuraavat päävaiheet (Kts. kuva 1-7): 1. Ohjelman lataus kiintolevyltä tietokoneen keskusmuistiin 2. Ohjelman suorittamisen aloitus ensimmäisestä käskystä (Yleensä pienin osoite ohjelmalle keskusmuistista varatulta alueelta.). 3. Ohjelman suorittaminen käsky kerrallaan. Prosessori lukee yhden käskyn kerrallaan keskusmuistista sisäänsä tulkitsee käskyn ja purkaa sen ns. mikrokoodin avulla pienempiin palasiin. Suorittaa käskyyn liittyneet tehtävät ja lukee taas uuden käskyn keskusmuistista jne 4. Ohjelman lopetus, ohjelmalle varattu tila keskusmuistista vapautetaan. KESKUSMUISTI KJ Ohjelma.EXE 1. 2. - 4. Prosessori KIINTOLEVY Ohjelmalle varattu muistialue Kuva 1-7. Ohjelman suorittamisen päävaiheet. 1.5 C-kielen muistialueet (Memory map) Käännetty ja suorituksessa oleva C-kielinen ohjelma käyttää neljää toisistaan erillistä muistialuetta. Kuvassa 1-8 on esitetty C-kielisen ohjelman käyttämät muistialueet. Pino Keko Globaalit muuttujat Suoritettava ohjelma Kuva 1-8. Periaatteellinen kuva C-kielisen ohjelman käyttämistä muistialueista. 13
Suoritettava ohjelma sijoitetaan omalle alueelleen muistissa. Tämä alue pysyy muuttumattomana koko ohjelman suorituksen ajan. Seuraava alue on ohjelman globaaleja muuttujia varten. Tälle alueelle on talletettu kaikki ohjelman globaalit muuttujat. Keko (Heap) on vapaata muistialuetta, jota ohjelma voi varata käyttöönsä (Allocation) dynaamisen muistin varaamiseen tarkoitetuilla funktioilla. Pino (Stack) on pääsääntöisesti väliaikaiseen talletukseen tarkoitettu muistialue. Pinossa pidetään mm. seuraavia asioita tallessa: Funktiokutsujen paluuosoitteet, Funktiokutsujen välitysparametrit, Paikalliset muuttujat ja Tietoja CPU:n tilasta. Näiden neljän alueen fyysinen toteutus vaihtelee eri prosessoreiden/kontrollereiden tyyppien ja C:n toteutuksen mukaan. 1.6 C-kielisen lähdetekstitiedoston nimeäminen C-kielisen lähdetekstitiedoston nimi jakaantuu kahteen osaan. Ensimmäisen osan muodostaa ohjelmoijan itsensä ohjelmalle antama nimi esimerkiksi OmaOhjelma. Toisen osan muodostaa ns. laajennusosa (Extension).C, joka on tämä sama kaikissa C-kielisissä ohjelmissa. Ohjelman koko nimi voisi tällöin olla OmaOhjelma.c. Laajennus osa kertoo sen minkä tyyppisestä ohjelmasta (lähdekoodista) on kysymys. Laajennusosan perusteella osataan täten valita sopivan tyyppinen kääntäjä, joka kääntää lähdetekstitiedoston sekä ohjelmalle sopivat käännösoptiot. 14