Programmeringssproget C – en introduksjon beregnet på elever ved Oslo By Steinerskole, datalinjen.

Av Hans Poppe

(Kilder: www.howstuffworks.com, How to program C, Dietel & Dietel 2000,
diverse ressurser på Internet)

1.1 Hva er et programmeringssprog?

Når en datamaskin skal “gjøre noe” kreves det alltid et program som kan styre inndata, utdata og all maskinvare som er i datamaskinen. Dette er rett og slett instruksjoner som gjør at metall og silikon kan samarbeide med strømpulser og vi kan få et fornuftig resultat ut av det hele. Det er vel ikke mange som kjøper en datamaskin bare for å ha den stående i et rom til utstilling? De er da ikke så fancy å se på? Ikke har de spesielt spennende og innovativt design heller.

De som skriver disse programmene kaller vi programmerere, og det de skriver (som efter hvert blir et program) kaller vi kode. Denne koden kan skrives i et av flere hundre programmeringssprog som er tilgjengelige i verden. Selv om det finnes hundrevis, ja kanskje tusenvis av forskjellige programmeringssprog kan all slike sprog deles opp i tre hovedtyper:

  1. Maskinsprog (machine language)

  2. Assemblersprog (assembly languages)

  3. Høynivåsprog (high-level languages)

En datamaskin kan egentlig bare forstå sitt eget maskinsprog. Maskinsproget kan vi godt si at er et slags naturlig sprog for den spesielle maskintypen. Hvilket maskinsprog en bestemt datamaskin “snakker” blir avgjort av hvilken type maskinvare som er i maskinen, spesielt prosessorens arkitektur. Maskinsproget er derfor maskinavhengig. Maskinsproget som benyttes av en Apple Macintosh er ikke det samme som brukes av en PC med prosessor fra Intel. Maskinsprog består av serier av tall, strengt tatt serier av 0 og 1-tall. Disse tallene gir maskinen beskjeder om hva som skal gjøres, om det er noe som skal regnes ut, om det er noe som skal vurderes som likt eller ulikt, eller om det skal skrives data til harddisk, eller leses fra harddisken og lignende ting. Det dreier seg altså om instruksjoner som styrer de helt elementære operasjonene i datamaskinen.
Maskinsprog er svært vanskelig og slitsomt å lese for mennesker. Hvis vi ser på et eksempel på maskinsprog i et program som legger til moms på en vare som skal selges i en forretning så ser vi raskt hva som menes med tungvindt. Her tar vi inntakskost, legger til moms og får pris med moms som lagres i siste linje.

+3421665439806

+1000054072000

+3811110650466

Etterhvert som datamaskiner ble stadig mer populære i de store massene ble det raskt klart at det å programmere i maskinsprog ble alt for tregt, det ble meget vanskelig og det krevet mye kunnskap å få det til. Det var svært lett å gjøre feil.
Av disse årsakene begynte programmerere å bruke Engelsk-lignende forkortelser for en del av de vanligste operasjonene fremfor å skrive inn disse lange seriene med tall. Disse “engelsk-lignende” forkortelsene ble basis (grunnlaget) for Assemblersprog. Det ble også, samtidig utviklet programmer som kunne oversette disse forkortelsene til maskinsprog. Disse programmene kalte man assemblere. De var et viktig skritt i utviklingen fordi de kunne oversette til maskinsprog i maskin-hastighet! Nå ble det meget lettere å programmere og det gikk betydelig fortere.
Hvis vi tenker oss eksemplet med pris og moms skrevet ut i assemblersprog ville vi kunne få
noe à là dette:



LOAD inntakskost

ADD moms

STORE salgspris

Selv om dette ser relativt lett og forståelig ut for et menneske, er dette fullstendig uforståelig for en datamaskin. Dette må oversettes til maskinsprog før computeren vil kunne gjøre noe i det hele tatt. Efter at assemblerne kom ble det fart i utviklingen av programmer og bruk av datamaskiner ble mer tilgjengelig og dermed mer populært og vanlig. Dette førte igjen til større efterspørsel, og så er det i gang...

Selv om assemblersprog og assemblere gjorde livet lettere for programmererne var det fremdeles mye arbeid og mye kode som skulle skrives, selv for enkle oppgaver som vi ønsket å få utført.
For å få litt fortgang på dette, ble det utviklet høynivåsprog, og i disse sprogene er det slik at selv enkle instruksjoner kan gi opphav til kompliserte rutiner. Det ble også utviklet oversetterverktøy, som kalles kompilator (compiler) som kan oversette høynivåkode til maskinsprog.
Høynivåsprogene gir programmererne anledning til å skrive programmer, nesten som om det skulle være engelsk (nesten). Man kunne også bruke vanlige matematiske tegn som +, -, * osv.
Den lille kodesnutten vi så på i sted kunne vært skrevet slik:

salgspris = inntakskost + moms

Det er lett å se hvorfor programmerere foretrekker høynivåsprog fremfor maskinsprog eller assemblerkode. Av de hundrevis av høynivåsprog som finnes er C og C++ svært mye brukt. Senere har også Java kommet til og blitt meget populært. Det finnes en rekke andre for eksempel Ada, som er oppkalt efter Ada Byron (Countess of Lovelace), datter av Lord Byron og kjent som verdens første programmerer. Fortran er et eksempel på et høynivåsprog som er spesielt utviklet for å løse kompliserte matematiske problemer. BASIC og SIMULA er eksempler på høynivåsprog som er skrevet spesielt for bruk i undervisning av nye programmerere. SIMULA er forresten utviklet i Norge.

Prosessen med å kompilere, altså gjøre høynivåsprog om til kjørbar maskinkode kan ofte ta mye tid og kreve ganske store ressurser. Dette problemet er delvis løst ved at det er utviklet interpretatorer (oversettere), programmer som kan lese høynivåsprog og oversette til maskinkode med det samme; à là minute, som man sier på Fransk. Selv om et program som er kompilert vil kjøre raskere, er det ganske vanlig å bruke slike interpretere, spesielt i miljøer hvor man driver med programutvikling. Det er veldig tidkrevende å kompilere et stort program bare for å se resultatet av små endringer. Da velger man ofte at det heller går litt saktere i eksekveringen (selve kjøringen), fordi det totalt sett er raskere enn å kompilere og så kjøre programmet. Det er først når programmet er blitt såpass utviklet at det er klart for salg, at man kompilerer og distribuerer på CD el.l.

Litt historisk om programmeringssproget C:

Programmeringssproget C stammer egentlig fra to andre, eldre sprog, nemlig BCPL og B.
BCPL står for Basic Combined Programming Language, et sprog som ble skrevet av Martin Richards i 1966 og tatt i bruk ved MIT (Michigan Institute og Technology) i 1977. Det er vanlig å si at sproget er fra 1977. B ble skrevet av Ken Thompson i 1970 og det var kraftig influert av BCPL, selv om det egentlig var en videreutvikling av et tidligere sprog han skrev, nemlig “bon”, som igjen var oppkalt efter hans kone; Bonnie. Ken Thompson gikk senere sammen med Dennis Ritchie som regnes som den (de) som skrev C. C ble første gang brukt i Bell Laboratories i en datamaskin av typen DEC PDP-7, og ble brukt i de første implementasjonene av operativsystemet UNIX. Dette skjedde i 1972.
C ble fort kjent som det beste utviklersproget for operativsystemet UNIX, og i dag er det fremdeles slik at alle de store operativsystemene er skrevet i C (og delvis i C++). I de siste 20 årene har C blitt tilgjengelig for stort sett alle operativsystem. C er uavhengig av maskinvare det betyr at det kan brukes på er rekke datasystemer med forskjellig maskinvare, det vil si med forskjellig prosessorarkitektur. Dette betyr også at hvis man skriver kode i C med omhu, kan denne koden portes til andre operativsystemer enn det som er på maskinen hvor vi skriver koden. Porting betyr å kompilere på en måte som er tilpasset en annen maskinvare (prosessor) enn det programmet opprinnelig ble skrevet for.

Innen utgangen av 70-årene hadde C utviklet seg til det som nå kalles tradisjonell C, også kjent som klassisk C. I 1978 utga Kernighan og Ritchie sin bok: “C the programming language” som gav sproget en betydelig interesse og boken ble efter hvert en av historiens best selgende bok innen feltet computervitenskap.

Det faktum at C ble tilpasset en lang rekke maskinvareplattformer på kort tid gjorde at sproget ble populært og fikk stor utbredelse, men det førte også til at det var flere forskjellige variasjoner (versjoner) som ikke var kompatible. Dette ble efterhvert et alvorlig problem for programmerere som ønsket å skrive applikasjoner, eller operativsystemutvikling på forskjellige plattformer, det vil si forskjellige maskinvarearkitekturer.
Det ble klart at det var behov for en standardisert versjon av C.
I 1983 dannet American National Standards Committee on Computers and Information Prosessing (X3) en underkommite som ble kalt X3J11. Denne komiteen fikk i oppgave å “provide an unambigous and machine-independent definition of the language”, skaffe en frittstående og maskinvareuavhengig versjon av sproget. Standarden bli akseptert i 1989 og senere oppdatert i 1999. Dokumentene som inneholder disse standardene heter ISO/IEC 9899:1999 og kan bestilles fra ANSI.
I dette kompendiet kommer vi ikke så mye inn på temaet porting, dette er ment å være et grunnkurs.
I alle fall er det slik at standardene vanligvis bare blir oppfattet som retningsgivende, de fleste programmerere vil med tiden utvikle sin egen stil og teknikk.

Standard biblioteket i C:

Efterhvert som du blir den dyktige C programmereren du kommer til å bli, vil du også oppdage at det er fullt mulig å skrive ALT, helt fra grunnen i et C program, også alle den typen kode og delene som vi kaller moduler. Du kan godt gjøre det selv, men det er mye arbeid og tar lang tid. Det er også lett å gjøre feil når man skriver kode, og jo mer man skriver desto større er sjansen for at det oppstår en eller annen trykkleif.
Derfor vil de fleste programmerere velge å bruke de standard C bibliotekene som finnes. Disse er nøye utprøvet av mange programmerere over flere år og vi kan være sikre på at det ikke er feil der av betydning. Et bibliotek er, i denne sammenhengen, en samling funksjoner som er skrevet av andre og som man kan benytte seg av uten å måtte skrive all koden en gang til.
For de som vil bli skikkelig mestre i C programmering er det helt nødvendig å lese boken “The Standard C Library” av P.J. Plauger. Dette gjelder særlig dersom du har lyst til å skrive kode som kan portes til flere systemer.
Man kan derfor si at det å bli en dyktig C programmerer krever to ting; både å kunne sproget og å ha forståelse for hvordan bibliotekene virker. Det finnes flere typer biblioteker, det vanligste kalles stdio.h (standard I/O), men math.h er også mye brukt av de som vil skrive løsninger for matematiske problemer.

I dette kompendiet er det ikke meningen at vi skal finne opp hjulet på nytt, vi skal heller ikke gå i dybden med hensyn til hvordan bibliotekfunksjonene virker, vi kaster oss rett ut i det hele i steden.

Husk at du alltid har tre gode innfallsvinkler:

  1. Standard bibliotekfunksjoner i C.

  2. Funksjoner du skriver selv.

  3. Funksjoner andre har skrevet og gjort tilgjengelige for deg, f. eks. På Internet.

Fordelen ved å skrive funksjoner selv er at du vet helt, nøyaktig hvordan de virker.
Ulempen er all den tiden som går med til å gjøre dette selv.

Programmeringens viktigste trend; objektorientering.

I tidligere tider kunne det være svært frustrerende å være programmerer, spesielt hvis man deltok i store prosjekter. Man kunne ende opp med å arbeide i måneder (og kanskje år), bare for å få beskjed om at prosjektet er: “nedlagt da det ikke ser ut til å kunne lykkes”. Det som var problemet var at all kode måtte skrives helt ferdig, og kompileres før man kunne se om det virket. Dersom det var et stort prosjekt (f.eks. et nytt operativsystem) kunne det ta lang tid før man oppdaget at det gikk i feil retning og at prosjektet ikke var levedyktig. Dette var, naturligvis, en dyr og tungvindt måte å teste programvare på.
Det er et stadig sterkere krav om at programvareutvikling skal gå stadig fortere, være mer feilfri og mer økonomisk hele tiden.
Objekter er i sin egentlige form rett og slett biter med kode (komponenter) som kan brukes om igjen.
Disse objektene kalles også
moduler.
Programmerere har forstått at det å bruke en
modulbasert, objektorientert tilnærming til programmeringen kan gjøre arbeidet mye lettere og mye raskere. I steden for å sette seg ned og skrive en kode som f.eks. kan skrive ut et dokument, kan man legge til en utskriftsrutine som noen andre har skrevet, eller som du har laget selv, men ikke gidder skrive flere ganger.
Objektorientert kode er ofte lettere å forstå og å feilrette enn det man tidligere brukte; nemlig
strukturert programmering.

Forbedringer i forhold til kode slik den ble skrevet i riktig gamle dager :-) begynte på 70-tallet. Det begynte med det som kaltes strukturert programmering, noe som ble popularisert sent på 70-tallet. I mange tilfelle var det slik at strukturert programmering ble det samme som programmering hvor man unngikk å bruke rutiner som gosub, noe som iverksatte under-rutiner i programmer. Disse var det meget vanskelig å feilsøke.

Hvis man skal være korrekt, stammer objekt-teknologi tilbake helt til midten av 1960 tallet. Da Bjarne Stroustrup skrev programmeringssproget C++, som regnes som det objektorienterte sproget, var det basert på to andre sprog; C, som opprinnelig ble utviklet hos AT&T for bruk i UNIX og Simula 67, et simuleringssprog utviklet i Norge (av bl.a. Kristen Nygaard) og utgitt i 1967. C++ tok opp i seg styrken i C og objektorientering og manipulering fra Simula 67.
Hverken C eller C++ var i utgangspunktet ment for bruk utenfor AT&Ts laboratorier, men folk likte sprogene og de fikk støtte “langt ned i grasrota”
.

Hva er disse objektene egentlig, og hva er det som gjør dem spesielle?
Objektteknologi er en måte å “pakke inn” kode på en slik måte at de blir meningsfylte deler av et større program. Det kan laves objekter av “alt”. Man kan tenke seg lyd-objekter,, dato-objekter, tids-objekter, fil-objekter, faktura-objekter, lønnings-objekter, tabell-objekter også videre også videre. Stort sett alle substantiver kan ha endelsen “-objekt” etter seg.
Vi lever i en verden av “objekter”. Bare se deg rundt. Det er mennesker, dyr, bygninger, biler, fly, tog, trær, blomster etc. etc. overalt.
Før objektorienteringen kom var programmeringssprogene (som for eksempel FORTRAN, Pascal, Basic og C) fokusert på handlinger (verb) fremfor objekter (substantiver). Programmerere som ellers levde i en objektorientert verden måtte “snakke” til datamaskinen, hovedsaklig ved bruk av verb. Dette skiftet i paradigmet kunne være mer enn bare litt frustrerende. Det ble rett og slett vanskelig. Nå er situasjonen endret, programmerere som lever og ånder i en objektorientert verden kan bruke objektorienterte sprog i programmeringen. Dette betyr, for de fleste, at de kan programmere på samme måte (eller nokså likt) som de oppfatter verden. Dette er mer naturlig for de fleste og har resultert i betydelige forbedringer, rett og slett fordi det oppfattes som mer naturlig av de fleste programmerere enn en prosedyre orientert tilnærming.

Noen programvareselskaper forteller at det ikke egentlig er det at koden kan brukes flere ganger som er det viktigste ved objektorientert kode, det er heller det at den er lettere å forstå, lese, feilsøke og holde vedlike, samtidig som den skal videreutvikles. Dette kan være ganske betydelig eftersom omlag 80 % av omkostningene ved produksjon av software ligger i feilsøking, debugging og videreutvikling samt vedlikehold.

Fordelen ved å skrive kode selv er at du vet nøyaktig hva den inneholder og hvorledes den er skrevet. Det blir lett å lese. Ulempen er at det tar lang tid og er til dels meget arbeidskrevende å skrive kode.

Andre høynivåsprog:

Det finnes, bokstavelig talt, hundrevis av høynivåsprog i verden. Allikevel er det ikke så veldig mange som er i alminnelig bruk. Det vil ikke være helt unaturlig å begynne med å nevne:

Java:

Utviklet av Sun Microsystems gjennom et prosjekt de kalte “Green” i 1991. De første versjonene ble lavet av James Gosling, basert på C og C++. Han kalte opprinnelig sproget for “Oak”, oppkalt efter et stort eiketre som sto utenfor vinduet hans i kontorene til Sun Microsystems. Det ble senere oppdaget at det allerede var et sprog som het Oak, og noen foreslo Java og det ble det.
Styrken i Java ligger mye i at det er utviklet for å være
maskinvareuavhengig. Det ble først tatt skikkelig i bruk efter 1993, da World Wide Web ble oppfunnet og man så mulighetene i Java til å lave bl.a. Dynamiske websider.

Fortran:

Fortran (FORmula TRANslator) ble utviklet av IBM mellom 1954 og 1957 (leeenge siden), til bruk i vitenskaplige programmer for å løse matematiske problemer. Fortran er fremdeles mye i bruk der det skal løses komplekse regnestykker.

COBOL:

Cobol (COmmon Business Oriented Language) ble lavet i 1959 av myndighetene i USA i fellesskap med store industriselskaper og individuelle programmerere. Sprogets styrke er dets evne til å manipulere meget store mengder med data. Fremdeles skrives store mengder med programmer for forretningsvirksomhet og statsforvaltning i COBOL. Et godt eksempel kunne være banker som kan ha millioner av transaksjoner, alle er enkle, men det er myriader av dem. Rikstrygdeverket her i Norge er et eksempel på en bedrift som fremdeles har programvare som delvis er basert på COBOL.

Pascal:

Pascal, oppkalt efter matematikeren og filosofen Blaise Pascal, ble utviklet av professor Niclaus Wirth omtrent på samme tid som C ble laget, spesifikt i 1971. Hovedsaklig beregnet til akademisk bruk, spesielt for å undervise i strukturert programmering. Dessverre mangler sproget viktige elementer som kreves for å få suksess i programutvikling for industri, forretningsvirksomhet og statsforvaltning.

Ada:

Programmeringssproget Ada, oppkalt efter Ada Byron, Countess of Lovlace, datter av den engelske poet Lord Byron, ble utviklet på 1970 og (tidlig) 1980 tallet av DOD (Department of Defence i USA). DOD hadde massevis av programvare, skrevet i hundrevis av sprog, og de ønsket en standardisering. Basis var Pascal, men det endelige resultatet ble svært forskjellig fra Pascal. Som nevnt ble det oppkalt efter Ada Byron (Lady Lovelace) som er kjent for å ha skrevet verdens første program, beregnet på The Analytical Engine lavet av Charles Babbage. En meget viktig side ved Ada er evnen til å tackle multi-tasking. Dette betyr at programmet kan gjøre flere ting samtidig, ikke bare i rask rekkefølge. Dette er IKKE tilfelle hverken for C eller C++. De kan bare utføre an handling av gangen.