1. Ohjelmointikielistä
Tässä luvussa kerrotaan mutkia oikoen hieman tietokoneen ideasta ja ohjelmointikielistä. Asiasta tulee tarkemmin ja lisää Tietokoneen rakenne ja arkkitehtuurikurssilla sekä Käyttöjärjestelmät. Asiaa sivutaan myös luvussa Lukujen esitys tietokoneessa.
1.1 Prosessori ja konekieli
Tietokoneen tärkeimmät osat ovat prosessori ja muisti. Prosessorin oleellinen ominaisuus on se, että sillä on tiedossa suoritettava käsky. Yleensä tämä tieto on IP-rekisterissä (Instruction Pointer, myös PC = Program Counter on yleisesti käytetty termi tälle). IP-rekisteri osoittaa koneessa muistipaikkaan, josta löytyy suoritettava käsky. Prosessorin toiminta on periaatteessa hyvin yksinkertaista:
- hae käsky IP-rekisterin osoittamasta paikasta
- kasvata IP-rekisterin sisältöä niin, että se osoittaa seuraavan käskyyn
- suorita haettu käsky (voi muuttaa IP:tä JUMP-käskyillä)
- jatka kohdasta 1.
Rekisterit ovat prosessorin sisäisiä nopeita muistipaikkoja. Käskyt ovat usein hyvin alkeellisia tyyliin:
- hae luku muistipaikasta 7F34 rekisteriin AX
- lisää rekisteriin AX rekisterin BX arvo
Jokaisella käskyllä on oma numeerinen arvo, joka tietokoneessa tietysti esitetään bitteinä. Esimerkiksi käsky
- laita luku 62 (heksaluku) rekisteriin BL
olisi Intel x86 -sarjan prosessorissa
B3 62
ja muistissa siis binäärisenä
10110011 01100010
Eli periaatteessa ohjelmointi olisi saada koneen muistiin noita oikeita binäärilukuja. Koska binäärilukuja on aika vaikea ihmisen hahmottaa, käytetään niille usein edellä olevaa heksalukuesitystä. Tuokaan ei ole ihan helppoa muistaa, että B3
tarkoittaisi, että "laita BL rekisteriin". Siksi käytetään yleensä assembly-kieltä, jossa on suurin piirtein 1:1 vastaavuus konekielisen binääriluvun ja ihmisen luettavan mnemonicin (muistikas) välillä. Eli eräällä (niitä on monia variantteja) assembly-kielellä edellinen komento olisi
mov bl,$62
Aluksi tietokoneita ohjelmoitiinkin syöttämällä suoraan käskyjen numeroarvoja. Sitten assembly-kielten myötä ihminen kirjoitti assembly-kieltä ja se käännettiin noiksi numeroarvoiksi ja näin saatiin syntymään koneen muistiin tarvittava ohjelma.
Koska prosessorin käskyt ovat varsin "alkeellisia", tarvitaan niitä paljon yksinkertaisenkin ohjelman tekemiseksi. Erityisesti tiedon lukemiseksi ihmissyötteestä tai tiedostosta. Siksi tarvitaan käyttöjärjestelmä, joka tarjoaa usein tarvittavat ominaisuudet valmiina. Mutta siltikin assembly-kielillä joutuisi kirjoittamaan pieneenkin ohjelmaan paljon koodia.
1950-luvulta lähtien alettiin kehittämään ohjelmointikieliä, joilla ohjelmien kirjoittaminen olisi helpompaa ja selkeämpää kuin assemblerilla. Näin syntyi monia vieläkin käytössä olevia ohjelmointikieliä, kuten Fortran (1957), Lisp (1958), Cobol (1959) ja Pascal (1970). 70-luvulle tultaessa kieliä oli jo kymmeniä ellei jopa satoja, kun pienet kielet lasketaan mukaan.
1.2 C-kieli ja robotti
Kielen kääntäjä on ohjelma, joka lukee syötteenään ihmisen kirjoittaman selkokielisen (esim C#-kieli) ohjelmatiedoston (tekstitiedosto) ja tuottaa siitä binäärimuotoisen suoritettavan (executable) konekielisen tiedoston, joka voidaan sitten ajaa. Tämän takia esimerkiksi Windows-järjestelmässä ajettavan tiedoston nimen tarkentimena on usein .exe
. Kun ohjelma käynnistetään, on käyttöjärjestelmän tehtävä laittaa ohjelmakoodi koneen muistiin ja siirtää ohjelmalaskuri ohjelman ensimmäiseen käskyyn.
Jälkeenpäin tunnetuin 70-lukulainen käännettävä korkeamman tason kieli on C-kieli (1972). Ideana (kuten sen edeltäjissäkin) on nostaa abstraktiota ylemmäksi, eli voidaan suoraan sanoa esimerkiksi:
int a = 15;
int b = 23;
int c = a + b;
Jos vastaava kirjoitettaisiin konekielellä, joutuisi ohjelmoija itse miettimään mitä kohtaa muistista käyttää muuttujille a
, b
ja c
. C-ohjelmassa (ja kurssin käyttämässä C#) kääntäjä pitää kirjaa tarvittavista muistipaikoista ja aina kun puhutaan muuttujasta a
, kääntäjä kääntää konekieliseen koodiin viittauksen a:lle varattuun muistipaikkaan.
Kurssin demotehtävissä on esimerkkinä pieni robotti, joka osaa vain muutamia käskyjä. Tämä robotti toimii hyvin vastaavalla tavalla kuin prosessori. Esimerkiksi edellinen C-ohjelman osa (joka itse asiassa tuolta osin on täsmälleen samanlainen C#-kielellä) olisi robotilla:
Voit kokeilla robotin toimintaa painamalla Step
-painiketta. Harjoitustehtävänä voit muuttaa sen laskemaan yhteen kaikki Input-hihnalla olevat luvut (tosin tämä vaatii sopimuksen että esim hihnalla oleva 0 lopettaa laskemisen). Input hihnalle saat uusia lukuja laittamalla ne Preset input
-kohtaan ja painamalla Reset
. Run
-painikkeesta robotti suorittaa kerralla koko ohjelman.
Robotissa Program
-kohdassa oleva keltainen rivi vastaa prosessorin IP-rekisteriä, eli osoittaa suoritettavaa käskyä.
Käytetty kieli on nyt tavallaan robotin assembly-kieltä.
Jos käskyille annettaisiin numeeriset arvot (joita niillä sisäisesti onkin), esimerkiksi:
00 = INPUT
01 = OUTPUT
02 = ADD
03 = SUB
04 = COPYTO
...
09 = JUMPIFNEG
olisi tämä ohjelma robotin "konekielellä":
00 04 00 00 02 00 01
jossa siis osa käskyistä vaatii kaksi tavua (tavu on 8 bittiä, esitetään kahden numeron pareina), kuten esim COPYTO
jossa on käskyn vastaava lukuarvo ja sitten käskyn kohteen osoite (nyt muistipaikka 00).
Sitten meillä voisi olla C-kääntäjä, joka kääntäisi aikaisemmin kuvatun ohjelman osan tuoksi lukujonoksi. Paitsi että muistipaikat a
ja b
tuossa tapauksessa kääntyisivät Input
-hihnalla oleviksi paikoiksi. Toki sama ohjelma voitaisiin tehdä myös muistipaikkoja käyttäen:
Tämä vastaisi jo melko tarkoin kirjoitettua C-ohjelmaa. Kääntäjän yksi tehtävä on silloin päättää, että vaikkapa muuttujasta a
puhuttaessa tarkoitetaan muistipaikkaa 00
ja b
:stä muistipaikkaa 01
.
1.3 Tavukielet
C-kieli oli valtakieli 70-luvun lopulta 80-luvun lopulle. 80-luvun alussa C-kielestä tehtiin alaspäin yhteensopiva oliolla laajennettu kieli C++
(1982). Myös tämä oli käännettävä kieli. 90-luvulla kehitettiin Java-kieli (1995) alun perin erilaisten sulautettujen järjestelmien kieleksi. Samalla Java paikkasi C++:n tunnettuja ongelmia. Javassa oli C++:aan nähden muutamia merkittäviä eroja:
- Javaa ei käännetä suoraan konekieleksi, vaan välikieleksi. Välikielistä tiedostoa ajetaan erikseen kullekin prosessorille tehdyllä Java-nimisellä ohjelmalla. Java-ohjelma (Java-virtuaalikone) lukee välikielen tavukoodia (vrt em robotin kielen lukuarvoinen esitys) ja suorittaa sitä askel kerrallaan. Java ei suinkaan ollut ensimmäinen tavukoodiin perustuva kieli, mutta se on tunnetuin tämän hetken virtuaalikoneeseen pohjautuvista kielistä.
- Javassa on automaattinen muistinhallinta, eli ohjelmoijan ei itse tarvitse muistaa vapauttaa varaamiaan muistialueita. Toki automaattinen muistinhallinta oli jo "tuttua" tekniikkaa vanhemmista kielistä.
- Javassa ei voi vahingossa osoittaa muistiin, jota ei ole varannut käyttötarkoitukseen (sanotaan ettei Javassa ole osoittimia)
Tavukoodin ideana on, että kääntäjää ei tarvitse tehdä erikseen joka prosessoriarkkitehtuurille ja käyttöjärjestelmälle. Riittää olla yksi kääntäjä, joka tuottaa välikooditiedoston (Javassa yleensä .class
). Toisaalta ohjelman suorittaminen vaatii sitten välikielen tulkitsemista todellisen prosessorin konekielelle ja aluksi Java-ohjelmat olivatkin hitaampia kuin C-ohjelmat. Nykyisin Java-kääntäjien kehitykseen on panostettu paljon ja lisäksi tavukoodia suoritettaessa sitä käännetään samalla konekielelle (JIT = Just In Time compiling) ja näin jos samaan koodin kohtaan tullaan uudelleen, se onkin valmiiksi käännetty ja suoritusnopeus ei eroa oleellisesti C-koodin suoritusnopeudesta.
Javan suosio ponnahti raketin lailla 90-luvun puolivälin jälkeen. VL:n mielipide syistä:
Syynä oli automaattisen muistinhallinnan ja helpommin vähemmän virheitä sisältävän ohjelmakoodin tuottaminen. Lisäksi Javassa oli toimivat merkkijonot, jotka puuttuivat esimerkiksi C++ standardista tuohon aikaan. Asiaa auttoi myös hyvin paljon C:tä muistuttava syntaksi, joka loivensi kielen vaihtoa."
Microsoft oli panostanut paljon C++ -kieleen, mutta huomasi Javan suosion nousun ja otti sen myös käyttöönsä, kuitenkin lisäten siihen omia ominaisuuksiaan. Tämä aiheutti lisenssiriitoja Javan kehittäneen Sun-yhtiön kanssa. Tästä syystä Microsoft lähti kehittämään omaa kieltä, jossa olisi kaikki Javan hyvät ominaisuudet. Tuloksena oli C#-kieli (C sharp, 2000). Monilta ominaisuuksiltaan kielet ovat hyvin samankaltaisia ja niiden välillä on aika helppoa ohjelmoijan siirtyä.
1.4 C# ja Jypeli
Jyväskylän yliopiston IT-tiedekunnassa ruvettiin miettimään nuorille sopivaa ohjelmointikurssia vuoden 2008-2009 tienoilla. Tällöin oli melko selkeää, että kurssilla pitäisi tehdä pelejä. Microsoftilla oli tällöin hyvät ympäristöt (Visual Studio) ja kirjastot (XNA) tehdä pelejä C#-kielellä ja saada ne toimimaan niin tietokoneissa kuin puhelimissakin (Windows Phone). Suoraan XNA:lla pelien ohjelmointi oli kuitenkin liian haastavaa ja siksi kehitettiin Jypeli-kirjasto, joka peittää alleen "turhia" yksityiskohtia, jotka jarruttaisivat aloittelevan ohjelmoijan ideointia. Tämä Nuorten pelikurssi osoittautui menestykseksi. Samaan aikaan takuttiin Java-pohjaisilla yliopiston ohjelmointikursseilla motivaation kanssa. Monia yliopistotason opiskelijoitakin pelit kiinnostavat ja siksi ensimmäiselle ohjelmointikurssille vaihdettiin teemaksi peliohjelmointi ja siinä samalla oli sujuvaa ottaa käyttöön Jypeli ja kieleksi C#. Tämä nostikin Ohjelmointi 1 -kurssin läpimenoa merkittävästi, kun voitiin tehdä "mielekkäämpiä" ohjelmia. Pelkkä Hello Worldin tulostaminen ei enää herättänyt intohimoa 2010-luvulla.
1.5 Muita kieliä
Edellä lueteltiin vain muutamia tunnettuja kieliä, C
, C++
, Java
ja C#
. Näillä on pitkälle samat sukujuuret. Puhuttiin myös välikielen tulkkaamisesta. Yksi hyvin tunnettu kokonaan alun perin tulkattavasi tehty kieli oli Basic
(1964). Ideana on silloin että käännösvaihe puuttuu ja ihmisen kirjoittamaa ohjelmakoodia ruvetaan suorittamaan suoraan rivi riviltä. Nykyisin Python
(1990) on noussut suosituksi tulkattavaksi kieleksi. Erilainen lähestymistapa ohjelmointiin on funktio-ohjelmointi, johon sopivia kieliä ovat esimerkiksi Haskell
(1990), Scala
(2004) ja F#
(2005).
Vastaavasti Javascript on selainten käyttämä kieli, jonka avulla alunperin staattiset HTML-sivut saadaan "elämään". Esimerkiksi tämä luentomoniste pyörii TIM-nimisessä sovelluksessa, jossa Pythonilla ja Haskelilla kirjoitettu palvelinohjelma lähettää selaimella Javascriptiä (1995) ja HTML:ää (1993), joiden avulla selain muodostaa interaktiivisen tekstin. Lisäksi TIMIä kirjoitettaessa käytetään nykyisin Javascriptin tilalla TypeScript-nimistä kieltä (2012), joka käännetään selainta varten Javascriptiksi. 3D-grafiikassa käytetään varjostinkieliä kuten GLSL ja HLSL riippumatta siitä, millä kielillä muut osiot grafiikkaa käyttävästä sovelluksesta kirjoitetaan. Eli käytännön elämässä yhden ohjelman kirjoittamisessa voidaan vaatia useiden eri ohjelmointikielten osaamista.
Eri kielten suosiosta ja historiasta voi katsoa lisää alla olevista linkeistä. Tosin kielten suosiota voidaan mitata hyvin eri tavoin, joten erilaisiin indekseihin kannattaa suhtautua kriittisesti.
Tällä kurssilla keskitytään kuitenkin käyttämään esimerkkinä C#-kieltä.
These are the current permissions for this document; please modify if needed. You can always modify these permissions from the manage page.