C (programspråk)
| Den här artikeln saknar källhänvisningar och kan därför inte verifieras. (2010-05) Förbättra artikeln genom att lägga till pålitliga källor (fotnoter). Information som inte verifieras, blir ifrågasatt och kan tas bort. Diskutera på diskussionssidan. |
| C | |
| Paradigm | imperativ, strukturerad |
|---|---|
| Gavs ut | 1972 |
| Skapat av | Dennis Ritchie på Bell Labs |
| Utvecklare | många |
| Senaste version | C11(8 december 2011) |
| Datatypsdisciplin | Statisk, stark |
| Stora implementationer | gcc, MSVC |
| Influerat av | B, Algol 68, Assembler |
| Influerat | C++, Objective-C, Java, Perl, PHP, JavaScript, C# |
| OS | Unix, Linux, Microsoft Windows, m. fl. |
| Licens | Öppen internationell standard, fri att implementera |
C är ett generellt, imperativt programspråk. Det tillhör familjen Algol-baserade språk och är avsett för strukturerad programmering.
C är ett av de mest inflytelserika högnivåspråken. Kompilatorer finns för nästan alla plattformar.[1][2] Det har också inspirerat många andra språk, som C++ och Java.
Innehåll
|
[redigera] Historia
Under slutet av 1960-talet började Unix utvecklas ur Multics vid dåvarande Bell Labs (nuvarande AT&T Bell Labs). Dennis Ritchie och Ken Thompson skrev det i assembler för minidatorn PDP-7. För att kunna skriva om det i ett högnivåspråk skapade Thompson med Ritchies hjälp programspråket B, en förenklad, minimalistisk version av BCPL anpassad för begränsat minnesutrymmet[3]. BCPL är i sin tur en förenklad version av CPL. B introducerade flera syntaktiska egenskaper som återfinns i C, såsom att jämförelser görs med dubbla likamedtecken. B började användas 1969.
B var dock inte ett generellt, plattformsoberoende programspråk. Det var anpassat för den hårdvara som det var skrivet på, PDP-7, och hade bland annat bara en enda datatyp (ordtypen). Ritchie påbörjade därför 1969 utvecklingen av ett nytt språk baserat på B, som han kallade för C, som skulle fungera på såväl mainframedatorer som mini- och mikrodatorer. Den första officiella versionen av Unix kom 1970. Det var då helt skrivet i assembler för PDP-11. Det motiverade än mer utvecklingen av C. Enligt Ritchie skedde den mesta utvecklingen av språket under 1972, och 1973 var det tillräckligt avancerat för att stora delar av Unix kunde skrivas om i det.
I Unix och C:s standardbibliotek anges tidsangivelser vanligen som antal sekunder sedan midnatt den 1 januari 1970, så kallad Unix time.
[redigera] K&R C
1978 gav Ritchie tillsammans med Brian Kernighan ut den första utgåvan av The C Programming Language, även känd som K&R efter "Kernighan & Ritchie".[4] Boken fungerade länge både som referensverk och som en informell specifikation av språket. De tidiga C-kompilatorerna var inte alltid så strikta med syntaxen, vilket ledde till viss frihet. Den version av C som introducerades i boken kallas för K&R C. Boken använde en formateringsstil, det vill säga regler för var man använder mellanslag och radbrytningar i källkoden, som lever kvar än i dag.
Några av de språkegenskaper som K&R introducerade var:
- ett standardbibliotek för I/O
- datatyperna "long int" och "unsigned int"
- ett entydigt sätt att skriva kortformer av tilldelning och operation på:
- kortform för tilldelningen
i=i-10(i tilldelas värdet av i minus 10) ändrades fråni=-10tilli-=10för att undvika sammanblandning med tilldelning av negativa tal,i=(-10)
- kortform för tilldelningen
Den andra utgåvan av boken kom 1988. Den behandlar det standardiserade ANSI C, som är mycket striktare i syntaxen.
[redigera] ANSI och ISO C (C89/C90/C95)
Under slutet av 1970-talet och början av 1980-talet skrevs C-kompilatorer för ett stort antal mainframedatorer, minidatorer och mikrodatorer. Dessa var inte alltid kompatibla med varandra. 1983 skapade ANSI en kommitté kallad X3J11 med målet att skapa en specifikation för C. Den ratificerades den 7 december 1989[5] som ANSI X3.159-1989 "Programming Language C". Denna variant av C refereras oftast till som ANSI C eller C89. Året därpå antogs ANSI C som ISO-standard med namnet ISO/IEC 9899:1990. Denna version kallas ibland C90, och är i praktiken identisk med C89.
Redan under arbetet med att anta ANSI C som ISO-standard lades nya förslag fram på utökningar och förbättringar. Eftersom behovet av en färdig standard var trängande togs dessa förslag inte upp för behandling. I stället behandlades de separat och samlades i ett tillägg som lades fram i september 1994 och antogs året därpå som ISO/IEC 9899:1990/Amd 1:1995. Detta tillägg kallas Normative Addendum 1, Amendment 1 eller C95.
ANSI C inkluderar många av de utökningar av språket som hade skett under årens gång. Dessutom lades några nya egenskaper till, bland annat funktionsprototyper och void-pekare. Vissa förbättringar kom från C++. I samband med detta infördes krav på att kompliatorn skulle kontrollera typerna på parametrar till funktioner. Innan C89 gjordes detta inte (externa funktioner deklararerades int my_func();), något som gjorde att en del ansåg C inte vara ett högnivåspråk.
Fortfarande flera år efter ratificeringen av ANSI C ansågs K&R C vara den minsta gemensamma nämnare som programmerare utvecklade för att maximera kodens kompatibilitet.
[redigera] C99
1995 gjordes några ändringar i ISO-standarden, bland annat för att förbättra stödet för olika teckenuppsättningar. 1999 kom en ny specifikation, ISO/IEC 9899:1999, vanligen kallad C99. C99 introducerade bland annat inline-funktioner, nya datatyper (long long int och complex) och officiellt stöd för radkommentarer som börjar med //, en syntaktisk funktion som fanns i BCPL och C++, och som redan stöddes av många C-kompilatorer.
C99 är mestadels bakåtkompatibel med C90, men är striktare i vissa avseenden. En funktionsdeklaration som saknar returtyp antas inte längre returnera en integer.
Stödet för C99 hos C-kompilatorer är ännu 2012 bristfälligt; många kompilatorer stöder stora delar, men få stöder allt. Bland de få som har fullt stöd finns IBM C.[6]
[redigera] C11
2007 påbörjades arbetet med en ny standard under det informella arbetsnamnet C1X. Den antogs i december 2011 som ISO/IEC 9899:2011, vanligen kallad C11. En stor nyhet i C11 var införandet av ett bibliotek för trådning samt stöd i språket för trådsäkra variabler och operationer.
Till följd av att stödet för C99 var så dåligt bland implementationer gjordes vissa delar av C11-standarden frivilliga att implementera, även sådana som är obligatoriska i C99. Ett exempel är stödet för komplexa typer, som är frivilligt i C11 men ett krav för C99-kompatibilitet. För att testa i fall en kompilator har stöd för komplexa typer och biblioteket <complex.h> kan man testa om makrot __STDC_NO_COMPLEX__ är definierat.
[redigera] Arvet från C
Att C utvecklades hand i hand med Unix gav det en mycket stark ställning inom Unix-världen, vilken det behåller än i dag. C är alltjämt mycket använt i exempelvis GNU och Linux. C blev tidigt det dominerande språket för utveckling på Microsoft Windows-plattformen, men trängdes ut av först C++ (via programbiblioteket Microsoft Foundation Classes), Delphi och Visual Basic, och sedermera C#.
För inbyggda system har C alltjämt en mycket stark ställning och för många hårdvarunära tillämpningar och realtidssystem är C fortfarande det dominerande språket. Starkt bidragande är att C-kompilatorer finns tillgängliga för de flesta plattformar. C har fördelen för hårdvarunära programmering att man har en rik flora olika heltalstyper och att man kan konvertera pekare ganska fritt.
[redigera] Relaterade språk
C är grund för flera andra moderna programspråk. I början av 1980-talet utvecklad Bjarne Stroustrup det objektorienterade språket C++, där konstruktioner hämtade från Simula 67 adderades till C. Det är delvis, men inte fullständigt, bakåtkompatibelt med C så att vissa program går att kompilera både som C och C++. C++ har i sin tur använts som grund för språk som Java och C#, som dock inte är bakåtkompatibla med vare sig C eller C++.
Objective-C är ett annat objektorienterat programspråk baserat på C, med influenser från Smalltalk. Det är till skillnad från C++ fullständigt bakåtkompatibelt med C, så att källkod skrivet i C kan kompileras med en Objective-C-kompilator.
[redigera] Syntax och uppbyggnad
C är skiftlägeskänsligt, det vill säga det skiljer på versaler och gemener i nyckelord och namn. Av praxis används versaler sällan utom i preprocessordirektiv och konstanter.
[redigera] Satser och block
Varje sats i C är ett kommando som avslutas med ett semikolon, ;. I de flesta fall kan en sats bytas ut mot ett block av kod. Block skrivs inom klammerparenteser, { ... }.
Satser och block behöver inte vara på separata rader. Flera satser kan stå på samma rad, och en sats kan vara utspridd över flera rader. Whitespace, det vill säga radbrytningar, tabulatorer och mellanslag, behandlas i de flesta fall lika, och behövs bara mellan nyckelord och namn. Denna frihet ger möjligheten till olika kodformateringsstilar, varav en av de mest kända är den som Kernighan och Ritchie använde i The C Programming Language, den så kallade K&R-stilen.
Det främsta undantaget från whitespace-friheten är preprocessordirektiven, som måste stå först på raden och avslutas med en radbrytning eller en kommentar.
/* Preprocessordirektiv måste stå först på en egen rad. */ #include <stdio.h> /* En deklaration utspridd över flera rader. */ int main( int argc, char **argv) { /* Flera satser på samma rad. */ int a = 4; a = a * 4; return a; }
[redigera] Programflöde
C har flera sorters villkorliga satser och slingor som styr vilken kod som exekveras.
[redigera] Villkorliga satser
Det främsta sättet att göra villkorliga satser på är med if. if följs av ett logiskt uttryck inom parentes, och sedan en sats eller ett block som exekveras om och endast om det logiska uttrycket är sant. Detta kan valfritt följas av else och en sats eller ett block som exekveras om och endast om det logiska uttrycket är falskt.
if(a > 5) puts("a är större än 5."); else { puts("a är inte större än 5."); if(a < 5) puts("a är till och med mindre än 5."); }
Som komplement till if i situationer där en och samma variabel jämförs med flera värden finns switch-satsen. Den tar ett uttryck inom parentes och jämför resultatet med en lista av utfall. Utfallen skrivs med case före och ett kolon efter, och fungerar ungefär som radetiketter. Kodexekveringen fortsätter från respektive rad. Till skillnad från switch-satser i en del andra språk stannar exekveringen inte när nästa case börjar. Vill man lämna switch-satsen använder man break (eller, om man vill avbryta hela funktionen, return). Om ingen matchande case finns fortsätter exekveringen från default om det finns, annars hoppas satsen över.
I exemplet nedan testas variabeln a. Om a är lika med 1 fortsätter programmet från case 1. Om a är lika med 2 fortsätter programmet från case 2. Eftersom case 1 inte avslutas med break kommer exekveringen att fortsätta in i case 2 så att båda utskrifterna görs.
switch(a) { case 1: puts("a är lika med 1."); case 2: puts("a är lika med 1 eller 2."); break; case 3: case 4: case 5: puts("a är lika med 3, 4 eller 5."); break; default: puts("a:s värde var inte med i listan."); }
[redigera] Slingor
C har tre olika sorters slingor: for, while och do while.
for används vanligen för att iterera genom ett antal element, till exempel en lista, med hjälp av en räknare. for följs av en parentes med tre semikolonseparerade satser:
- En sats eller en variabeldefinition som körs före slingan; typiskt tilldelas här en räknare sitt startvärde.
- Ett villkor för om slingan upprepas eller inte.
- En sats som körs sist i slingan; typiskt räknas räknaren upp här.
Sedan följer ett kodblock (eller en sats) som utgör själva slingan.
När en for-slinga exekveras utförs först den första satsen. Om en variabel definieras i den första satsen sträcker sig dess definitionsområde endast till slingan, och kan inte användas efteråt. Sedan görs en test av villkoret; om det är falskt så avslutas slingan, annars exekveras kodblocket. När kodblocket har exekverats kommer den sista satsen från for-satsen. Sedan hoppar programmet tillbaka till villkoret och fortsätter därifrån.
/* Skriver ut n och kvadraten av n för n = 1 till 25. */ for(int n = 1; n <= 25; n++) { printf("%d %d\n", n, n*n); }
Alla tre delar i for-satsen är valfria och kan lämnas tomma. Villkoret räknas som alltid sant om det utlämnas.
while är en enklare slinga än for. Den följs av en parentes med endast ett villkor.
/* Upprepa slingan så länge som getchar() inte returnerar bokstaven 'a'. */ printf("Tryck på a för att fortsätta."); while(getchar() != 'a') { printf("Fel! Tryck på a."); } printf("Rätt!");
do while fungerar precis som while, förutom att villkoret inte testas före första exekveringen. do while-slingan är därför garanterad att exekveras åtminstone en gång.
/* Upprepa slingan så länge som getchar() inte returnerar bokstaven 'a'. */ do { printf("Tryck på a för att fortsätta."); } while(getchar() != 'a'); printf("Rätt!");
En slinga kan avbrytas i förtid med nyckelordet break. Exekveringen fortsätter då direkt efter slingan. Om programmet nästlar flera nivåer av slingor är det den närmaste som avbryts. Det går också att hoppa över resten av koden och fortsätta till nästa varv i slingan med nyckelordet continue. I for-slingor exekveras inkrementeringen, och i samtliga slingor testas villkoret.
[redigera] Ovillkorliga hopp
C tillhandahåller goto, men det används i praktiken mycket sparsamt. Med goto kan man hoppa till en valfri plats i koden. Denna plats identifieras med ett namn, en radetikett, och avslutas med ett kolon.
int a = 5; goto hopp; a = 7; /* Den här raden exekveras aldrig. */ hopp: printf("%d\n", a); /* Skriver alltid ut "5". */
Andra ovillkorliga hopp är continue, som hoppar till nästa iteration av en slinga; break, som hoppar ur en slinga eller switch-sats; och return, som hoppar ur en funktion.
[redigera] Funktioner
En funktion definieras i C med först en returtyp, sedan namnet på funktionen, och sist en kommaseparerad lista av parametrar inom parentes. Sedan följer ett kodblock med funktionens kod. Om funktionen har en returtyp (det vill säga inte void) avslutas den med nyckelordet return och returvärdet. return måste inte ligga sist i funktionen, utan kan användas till exempel i villkorliga satser för att avsluta en funktion innan den har nått slutet.
/* En funktion som returnerar summan av två heltal. */ int summa(int a, int b) { return a + b; }
Typdeklarationen av en funktions parametrar kan utelämnas ur funktionsdeklarationen och i stället skrivas före kodblocket. Före C99 var det tillåtet att helt utelämna typdeklarationen – sådana parametrar antogs då vara av typen int. Dessa skrivsätt är inte vanliga eller rekommenderade.
/* En funktion som returnerar summan av två heltal. */ int summa(a, b) int a, b; /* Denna rad är inte nödvändig i C-versioner före C99. */ { return a + b; }
Om en funktion ska anropas från ett ställe där den inte redan är definierad, till exempel tidigare i samma källkodsfil, i en annan källkodsfil eller förkompilerad i ett programbibliotek, så måste den först deklareras utan sitt kodblock så att kompilatorn känner till funktionens parametrar och returtyp. Denna deklaration sker vanligen i en headerfil som kan inkluderas från alla källkodsfiler som vill använda funktionen.
int summa(int a, int b);
En funktion som inte returnerar ett värde (ibland kallad för subrutin) ges den symboliska returtypen void. Om funktionen inte har några parametrar lämnas parentesen antingen tom eller med void.
Funktionen summa kan anropas med parametrar och dess returvärde kan fångas upp på följande sätt:
int x = summa(8, 13);
[redigera] main
Varje C-program måste innehålla en funktion som heter main. Det är i main som programmet startar, programmets entry point. Funktionen tar två parametrar. De innehåller de argument som har skickats till programmet: argc (argument count) är ett heltal som säger hur många argument som har skickats med, och argv (argument vector) är en lista av strängar med argumenten. Den första strängen i listan är alltid namnet på programmet självt, vanligen inklusive sökvägen. Funktionen returnerar ett heltal som typiskt fungerar som resultat eller felmeddelande till det anropande programmet.
/* Den normala deklarationen av main. */ int main(int argc, char **argc); /* I K&R C utelämnas vanligen parametrarna. */ int main(); /* Vissa kompilatorer tillåter att main inte returnerar något. */ void main(int argc, char **argc);
[redigera] Kommentarer
Kommentarer är fritext som en utvecklare kan lägga till källkoden, till exempel för att beskriva vad koden gör. Kommentarer påverkar inte programmet som sådant. En vanliga användning av kommentarer är också att maskera kod så att den inte kompileras med i programmet, vanligen i debugsyfte. Detta kallas ofta för bortkommentering av källkod. Kommentarer rensas bort internt av kompilatorn innan källkoden kompileras.
Kommentarer inleds med /* och avslutas med */. Detta kallas ibland för blockkommentarer för att skilja dem från radkommentarer, då de kan användas för att skriva kommentarer över flera rader.
Många C-kompilatorer erbjuder radkommentarer. Dessa startar med // och avlutas vid radbrytning. Denna typ av kommentarer fanns i BCPL men togs inte med i B och heller inte i Ritchies ursprungliga version av C eller i ANSI C. C++ tog däremot upp bruket, och i och med att många kompilatorer fungerar för både C och C++ spred sig bruket till C. Radkommentarer standardiserades i C99.
/* En blockkommentar som sträcker sig över flera rader. */ int j; // En radkommentar kan beskriva vad koden i början av raden gör.
[redigera] Preprocessordirektiv
Ett preprocessordirektiv är en instruktion till kompilatorn som modifierar källkoden innan den kompileras. Preprocessordirektiv inleds i C med #, som måste stå först på raden, och avslutas vid radbrytning. De vanligaste direktiven är #include, som vanligen används för att hämta funktionsdefinitioner och andra definitioner, och #define, som används för att skapa makron.
| Direktiv | Beskrivning |
|---|---|
| #define, #undef | Definierar ett makro. |
| #error | Genererar ett felmeddelande vid kompileringen. |
| #if, #else, #elif, #endif, #ifdef, #ifndef | Villkorliga block baserade på tester |
| #include | Inkluderar andra källkodsfiler, vanligen headerfiler. |
| #pragma | Kompilatorspecifika direktiv. |
[redigera] Variabler och datatyper
C har ett antal enkla datatyper. Storlekarna på dem är avsiktligt vagt definierade. Därför kan det vara svårt att porta källkod från ett system till ett annat, till exempel från ett 16-bitarssystem till ett 32-bitarssystem.
För att definiera en variabel i C skriver man först datatypen och sedan variabelnamnet och avslutar med semikolon. Flera variabler av samma typ kan definieras på samma gång. De separeras då av kommatecken.
/* Definiera två variabler i och j av typen int. */ int i, j;
Tilldelning av variabler görs med ett likamedtecken. Jämförelser görs med dubbla likamedtecken.
/* Om i är lika med 6 så tilldelas j värdet 1. */ if(i == 6) j = 1;
[redigera] Heltal
C har två grundläggande heltalsdatatyper:
char, som representerar teckendata. Storleken på encharär 1 byte, det vill säga den minsta adresserbara dataenheten som är minst 8 bit stor. Alla andra datatypers storlekar är multipler avchar.int, som vanligen är samma storlek som datorns ordtyp, typiskt 16 (garanterad minsta storlek), 32 eller 64 bitar.
De två heltalstyperna kan modifieras för att vara med eller utan tecken för att tillåta både positiva och negativa tal:
signed(med tecken)unsigned(utan tecken)
signed innebär att en bit avsätts för att skilja mellan negativa och positiva tal, oftast (men inte nödvändigtvis) i tvåkomplementsform. Om ingen av dessa två anges så impliceras signed för int-typen. För char varierar implementationen mellan olika kompilatorer.
Storleken på datatypen int kan modifieras:
shortellershort int, minst 16 bitarlongellerlong int, minst 32, ofta 64 bitarlong longellerlong long int, minst 64 bitar (sedan C99)
[redigera] Logiska/booleska värden
I C fanns ursprungligen ingen strikt boolesk typ, vars enda värden skulle vara sant och falskt. I stället används heltal av typen int, där värdet noll representerar falskt och ett (eller icke-noll) representerar sant. Alla logiska operationer returnerar int, och alla villkorliga satser tolkar noll som falskt och alla andra värden som sant.
/* Det logiska uttrycket "13 < 6" är falskt, så x får värdet 0. */ int x = 13 < 6; /* 7 är icke-noll. Det tolkas därför som sant och satsen exekveras alltid. */ if(7) { ... }
I C99 introducerades typen _Bool, med aliaset bool definierad i headerfilen bool.h, som en boolesk typ som kan anta värdena noll och ett för falskt respektive sant. Logiska operatorer är dock fortsatt av typen int.
[redigera] Flyttal
Det finns tre flyttalstyper:
Standarden specificerar inte vad det ska vara för format på flyttalen. I de flesta implementationer är float och double baserade på IEEE 754:s standarder för enkel (32 bitar) och dubbel (64 bitar) precision. Den största flyttalstypen, long double, har sämre stöd i standardbiblioteken, och dess implementation varierar mer mellan olika plattformar, från 64 till 128 bitar. Standarden garanterar inte att det är någon skillnad alls mellan de tre typerna, bara att double är minst lika stor som float, och att long double är minst lika stor som double.
I standardbiblioteken användes ursprungligen endast double; float behandlades som en minnessparande typ som konverteras till double vid funktionsanrop. I C99 infördes varianter av standardbibliotekens funktioner för float och long double, till exempel sinusfunktionen double sin(double) med varianterna float sinf(float) och long double sinl(long double).
[redigera] Komplexa tal
I C99 definierades en utökning för variabler som är komplexa tal. Dessa definieras med nyckelordet _Complex plus en flyttalstyp. Vanligen används complex, som är ett alias för _Complex men som bara finns tillgängligt om man inkluderar headerfilen complex.h. I samma headerfil finns konstanten I definierad som den imaginära enheten.
De vanliga flyttalstyperna räknas som reella tal. För rent imaginära tal kan man använda _Imaginary på samma sätt som _Complex, med ett motsvarande alias imaginary.
complex double z1, z2, z3; z1 = 5 + 2*I; /* 5 + 2i */ z2 = 1 - I; /* 1 - i */ z3 = z1 * z2; /* 7 - 3i */
[redigera] Listor och matriser
En lista (engelska: array) definieras genom att till variabelnamnet lägga hakparenteser mellan vilka man skriver listans längd. Längden kan utelämnas om man i definitionen sätter värden på listan. För att läsa eller ändra ett värde i en lista skriver man indexet inom hakparenteser efter variabelnamnet. Det första elementet i en lista har alltid index 0.
int a[5]; /* En array med 5 element. */ int b[] = {12, -4, 7, 112}; /* En array med fyra element */ a[4] = b[2]; /* Det sista elementet i a tilldelas värdet av det tredje i b, det vill säga talet 7. */
Rent syntaktiskt kan listan och indexet byta plats. Detta används dock sällan i praktiken eftersom det försvårar läsbarheten.
/* x och y tilldelas samma värde: det fjärde elementet i a. */ int x = a[3]; int y = 3[a];
En matris är en lista med två dimensioner, eller en lista av listor. På samma sätt kan man bygga matriser av ännu högre dimensioner.
int m[5][12]; /* En matris med 5×12 element. */ int q[10][10][10][10]; /* En fyrdimensionell matris med 10×10×10×10 element. */
Förutom vid definitionstillfället kan listor inte tilldelas i sin helhet, bara elementvis.
int a[5], b[5]; a = b; /* Inte möjligt. */
[redigera] Pekare
Pekare är en speciell datatyp som hänvisar till en adress i minnet där det egentliga datat finns. Pekarvariabler definieras med en datatyp och en asterisk framför pekarnamnet:
/* Definiera en variabel av typen int, och en pekare till typen int. */ int i, *p;
En pekare kan tilldelas adressen till en annan variabel av motsvarande datatyp genom att man sätter ett et-tecken framför variabln:
/* Gör så att p pekar på i. */ p = &i;
För att hämta eller manipulera värdet på den minnesadress som en pekare pekar på skriver man en asterisk framför pekaren:
/* Ändra värdet som p pekar på, det vill säga värdet av i. */ *p = 17;
En pekare kallas för en nullpekare när den pekar på minnesadressen 0. Detta räknas i princip alltid som att pekare är oinitierad och inte ännu bör användas. Att försöka att läsa från eller skriva till adress 0 leder i många moderna system till undantag eller att programmet kraschar.
Pekare kan användas som listor. Indexet multipliceras med datatypens storlek och adderas till minnesadressen innan värdet hämtas. På samma sätt fungerar listor som pekare till det första elementet i listan. En pekare kan tilldelas värdet av en lista; de pekar då samma minne och kan användas på samma sätt.
int *p, l[10]; p = l; /* p och l pekar på samma minne. */ p[2] = 7; /* Tilldelar l[2] värdet 7. */
[redigera] Strängar
Det finns ingen särskilt strängtyp i C, utan en sträng är detsamma som en lista av char-värden. Strängar avslutas med ett NULL-tecken, alltså en char med heltalsvärdet 0. När man reserverar minnesutrymme för en sträng måste man räkna med NULL-tecknet. Statiska strängar skrivs inom dubbla citattecken; NULL-tecknet är då implicit med.
Det finns inget i strängen som säger hur lång den är, eller hur mycket minne som den kan använda.
char c[] = "Hej!"; /* En sträng – eller en array med fem element (fyra skrivtecken plus implicit NULL) */
Eftersom strängar är listor eller pekare går de inte att jämföra som andra variabler. I stället används särskilda funktioner i C:s standardbibliotek string.h för sådana jämförelser:
char a[] = "Hello", b[] = "World"; /* Funktionen strcmp returnerar 0 om strängarna är lika. */ if(strcmp(a, b) == 0) puts("a och b är lika."); else puts("a och b är olika.");
[redigera] void
void är egentligen ingen datatyp, utan en symbol för när det inte finns någon datatyp. Den används i tre sammanhang:
- För att definiera att en funktion inte har en returtyp.
- För att definiera att en funktion inte tar några parametrar.
- För att definiera eller typkonvertera pekare som typen
void *, som kan peka på vilken annan typ som helst.
[redigera] Operatorer
[redigera] Aritmetiska operatorer
Resultatet av de aritmetiska operatorerna är värdet på operationen. Till exempel är resultatet av b = c lika med det nya värdet på b. Det värdet kan i sin tur tilldelas en annan variabel: a = b = c. Då tilldelas b värdet av c, och a tilldelas värdet av b = c, det vill säga också c. Undantaget är de unära operatorerna för inkrementering och dekrementering, som finns i två former: ett prefix som returnerar det nya värdet och ett suffix som returnerar det gamla.
| Operator | Syntax | Resultat (värde) |
|---|---|---|
| Tilldelning | a = b |
Värdet på a efter tilldelningen. Detta kan användas för att sätta flera variabler till samma värde: a = b = c = 7; |
| Addition | a + b |
Summan av a och b. |
| Subtraktion | a - b |
Differensen mellan a och b. |
| Unärt plus | +a |
Värdet på a. Om a är en mindre datatyp så konverteras den till signed int. |
| Unärt minus (negation) | -a |
Värdet på a med motsatt tecken. Om a är en mindre datatyp så konverteras den till signed int. |
| Multiplikation | a * b |
Produkten av a och b. |
| Division | a / b |
Kvoten av a och b. Vid heltalsdivision är resultatet ett heltal. |
| Modulo (rest vid division) | a % b |
Resten vid heltalsdivision av a med b. Fungerar endast på heltal. |
| Inkrement (prefix) | ++a |
a tilldelas värdet av a+1, och det nya värdet returneras. |
| Inkrement (suffix) | a++ |
a tilldelas värdet av a+1, och det gamla värdet returneras. |
| Dekrement (prefix) | --a |
a tilldelas värdet av a-1, och det nya värdet returneras. |
| Dekrement (suffix) | a-- |
a tilldelas värdet av a-1, och det gamla värdet returneras. |
[redigera] Jämförelseoperatorer
Jämförelseoperatorer används för att jämföra två variabler eller uttryck med varandra. Resultatet av en jämförelse är ett heltal av typen int med värdet noll för falskt och ett för sant.
| Operator | Syntax |
|---|---|
| Lika med | a == b |
| Ej lika med | a != b |
| Större än | a > b |
| Mindre än | a < b |
| Större än eller lika med | a >= b |
| Mindre än eller lika med | a <= b |
[redigera] Logiska operatorer
Logiska operatorer används på logiska (boolska) uttryck. Efter som C före C99 saknade en boolesk typ används heltal för att representera dessa värden: 0 betyder falskt och icke-0 sant. Resultatet av de logiska operatorerna är alltid 0 för falskt och 1 för sant.
| Operator | Syntax |
|---|---|
| Negation (ICKE) | !a |
| Konjunktion (OCH) | a && b |
| Inklusiv disjunktion (ELLER) | a || b |
[redigera] Bitoperatorer
Bitoperatorer används på heltal för att utföra operationer på binärrepresentationen av tal.
| Operator | Syntax |
|---|---|
| Bitvis negation (ICKE) | ~a |
| Bitvis konjunktion (OCH) | a & b |
| Bitvis inklusiv disjunktion (ELLER) | a | b |
| Bitvis exklusiv disjunktion (XOR) | a ^ b |
| Bitvis skiftning, vänster | a << b |
| Bitvis skiftning, höger | a >> b |
[redigera] Operatorer för sammansatt aritmetik och tilldelning
Redan i B fanns möjligheten att utföra en operation på en variabel och tilldela variabeln resultatet med en förenklad syntax. Fördelen är tydligast när vänsterledet är ett komplicerat uttryck, till exempel en listelement med ett artimetiskt uttryck som index. Resultatet av uttrycket är detsamma som vid en vanlig tilldelning.
/* Följande uttryck är ekvivalenta */ a = a * b; a *= b;
| Operator | Syntax |
|---|---|
| Addition och tilldelning | a += b |
| Subtraktion och tilldelning | a -= b |
| Multiplikation och tilldelning | a *= b |
| Division och tilldelning | a /= b |
| Modulo och tilldelning | a %= b |
| Bitvis konjunktion och tilldelning | a &= b |
| Bitvis inklusiv disjunktion och tilldelning | a |= b |
| Bitvis exklusiv disjunktion och tilldelning | a ^= b |
| Bitvis vänsterskiftning och tilldelning | a <<= b |
| Bitvis högerskiftning och tilldelning | a >>= b |
[redigera] Objekt-, pekar- och listoperatorer
| Operator | Syntax | Resultat |
|---|---|---|
| Listindex | a[b] |
Element nummer b från en lista a eller elementet på minnesposition a + b * s, där a är en pekare och s är storleken på datatypen som a pekar på. a och b kan byta plats i uttrycket. |
| Avreferering | *a |
Elementet som a pekar på; detsamma som a[0]. |
| Referering | &a |
En pekare till a. |
| Medlem (i objekt) | a.b |
Medlemmen b i a, där a är ett objekt av en strukturerad typ (struct eller union). |
| Medlem (i pekare) | a->b |
Medlemmen b i a, där a är en pekare till ett objekt av en strukturerad typ. |
[redigera] Övriga operatorer
| Operator | Syntax | Resultat |
|---|---|---|
| Funktionsanrop | a(a1, a2) |
Resultatet från funktionen a. |
| Komma | a, b |
b. |
| Villkorlig beräkning | a ? b : c |
b om a är sant (icke-noll), annars c. |
| Datatypstorlek | sizeof asizeof(typ) |
Storleken på objektet a eller datatypen typ i byte (multipler av char). Storleken är av heltalstypen size_t och inkluderar det eventuella utfyllnadsutrymme som kan krävas av systemet för att kunna adressera objekten. |
| Datajustering | _Alignof(a)_Alignof(typ) |
Datajusteringen (data alignment) för objektet a eller datatypen typ i byte (multipler av char). Storleken är av heltalstypen size_t. (Sedan C11.) |
| Typkonvertering | (typ) a |
Värdet av a efter typkonvertering. |
[redigera] Reserverade nyckelord
C är ett av de språk med lägst antal nyckelord (även kallat reserverade ord): 32 stycken i C89, 37 i C99 och 44 i C11. Nyckelord kan inte användas som namn på variabler, funktioner eller användardefinierade typer.
När namnen på de varibeltyper som introducerades i C99 och C11 skulle bestämmas togs hänsyn till att de kan krocka med användardefinierade typer och variabelnamn i källkod som är skrivna för äldre versioner av standarden. Därför har de fått namn som avviker från mönstret, till exempel _Complex. Genom att inkludera särskilda C99- eller C11-specifika header-filer fås tillgång till makron med mer typiska namn, till exempel complex.
Många kompilatorer har utöver dessa nyckelord en mindre grupp egna ord för olika kompilatorspecifika funktioner. Ett av de vanligaste är asm, som används för att skriva assemblerkod direkt i C-koden.
| Nyckelord | Standard | Beskrivning |
|---|---|---|
_Alignas |
C11 | Sätter datajusteringen (data alignment) hos ett objekt eller en typ. |
_Alignof |
C11 | Ger datajusteringen hos ett objekt eller en typ. |
_Atomic |
C11 | Används för att skapa variabler som kan användas till atomiska, trådsäkra operationer. |
auto |
Skrivs före en variabel. Anger att kompilatorn får välja hur variabeln lagras. Jämför register. |
|
_Bool |
C99 | En boolesk datatyp. Används oftast genom makrot bool. |
break |
Avbryter en do-, for-, switch- eller while-sats. |
|
case |
Anger alternativ i switch-satser. |
|
char |
En heltalstyp. | |
_Complex |
C99 | En komplex datatyp. Används oftast genom makrot complex. |
const |
Anger att en variabels värde inte kan ändras under körning. | |
continue |
Hoppar till slutet av en do-, for- eller while-sats. |
|
default |
Det alternativ i en switch-sats som väljs när inget av de andra alternativen valdes. |
|
do |
En slinga vars villkor kommer efter första blocket, så att det är garanterat att exekveras minst en gång. | |
double |
En datatyp för flyttal. | |
else |
Startar alternativgrenen i if-satser. |
|
enum |
Definierar uppräkningstyper. | |
extern |
Tillåter att en funktions kod eller variabels lagring finns i en annan modul är den nuvarande. | |
float |
En datatyp för flyttal. | |
for |
En slinga som vanligen används för att stega igenom listor eller liknande. | |
_Generic |
C11 | Används för att bygga typgeneriska makron. |
goto |
Sats för att flytta exekveringen till en annan del av koden (se goto). | |
if |
Villkorlig sats. | |
_Imaginary |
C99 | En imaginär datatyp. Används oftast genom makrot imaginary. |
inline |
C99 | Används för att göra koden snabbare genom att eliminera funktionsanrop för små funktioner. |
int |
En heltalstyp. | |
long |
En heltalstyp (även long long). |
|
_Noreturn |
C11 | Specificerar att en funktion inte kommer att returnera. |
register |
Skrivs före en variabel. Anger att kompilatorn om möjligt bör hålla denna variabel i ett processorregister. Jämför auto. |
|
restrict |
C99 | Används i funktionsdeklarationer för att tillåta kompilatorn att optimera koden som hanterar pekare genom att säga att två pekare inte får peka på samma minnesadress. |
return |
Avslutar en funktion. Om funktionen returnerar ett värde så måste return följas av ett sådant. |
|
short |
En heltalstyp. | |
signed |
Säger att en heltalstyp ska tillåta negativa värden. | |
sizeof |
Ger storleken i bytes av en datatyp. | |
static |
Deklarerar att en lokal variabel i en funktion ska behålla sitt värde mellan anrop. | |
_Static_assert |
C11 | Utför tester under kompileringen. |
struct |
En strukturerad datatyp. | |
switch |
En sats med flera villkor och flera alternativa exekveringsvägar. | |
_Thread_local |
C11 | Specificerar att en variabel är lokal för en tråd. |
typedef |
Typdefinitioner, ett sätt att förkorta och förtydliga namn på datatyper. | |
union |
En strukturerad datatyp där flera variabler delar på samma minnesutrymme. | |
unsigned |
Säger att en heltalstyp bara ska tillåta positiva värden. | |
void |
Säger att en funktion inte returnerar något värde eller inte tar några parametrar, eller att en pekare kan peka på vilken datatyp som helst. | |
volatile |
Skrivs före en variabel. Anger att kompilatorn inte får spara variabeln i ett register, eftersom dess värde kan ändras när som helst, till exempel av andra trådar. | |
while |
En slinga vars villkor kommer först, så att villkoret garanterat har testats före första exekveringen. Används även för villkoret i do-satser. |
[redigera] Programbibliotek och headerfiler
C har standardiserat ett relativt litet programbibliotek med funktioner för främst in- och utdata, sträng- och minneshantering, samt matematiska funktioner. För att komma åt dem måste de dels länkas in under kompileringen, dels göras tillgängliga genom inkludering av så kallade headerfiler. En headerfil är en källkodsfil med filändelsen .h, som innehåller definitioner av program, datastrukturer, makron och variabler som är externa, det vill säga inte är deklarerade i samma källkodsfil som det program eller de funktioner som använder dem.
Ett exempel är standardfunktionen printf som används för att formatera utskrifter till skärmen. Den är definierad i stdio.h. Själva funktionen finns vanligen i ett förkompilerat programbibliotek som länkas in under kompileringen av ett program. Ett program som vill använda printf måste inkludera stdio.h innan den anropar funktionen, vanligen alldeles i början av källkoden:
#include <stdio.h>
Genom att bara inkludera de headerfiler som behövs och bara länka in de programbibliotek som behövs kan storleken på ett C-program hållas nere.
De flesta kompilatorer tillhandahåller ett antal programbibliotek utöver de som är standard. Många av dem är mer eller mindre plattformsberoende, till exempel grafiska verktyg och bibliotek för trådning, något som helt saknas i standardbiblioteken.
[redigera] Lista över headerfiler
C89 innehåller 15 headerfiler för standardbiblioteket. I tillägg Normative Addendum 1 (NA1) tillkom tre headerfiler. I C99 utökades antalet till 24, och i C11 till 29.
| Headerfil | Standard | Beskrivning |
|---|---|---|
assert.h |
Innehåller makrot assert som används vid debugging. |
|
complex.h |
C99 | Innehåller funktioner och makron för komplexa tal. |
ctype.h |
Innehåller funktioner för att klassificera och konvertera tecken. | |
errno.h |
Innehåller makron för att testa felkoder från standardbiblioteket. | |
fenv.h |
C99 | Innehåller makron och funktioner för att kontrollera flyttalsmiljön. |
float.h |
Innehåller konstanter som definierar flyttalsmiljön. | |
inttypes.h |
C99 | Innehåller funktioner för konvertering mellan heltalstyper. |
iso646.h |
NA1 | Innehåller definitioner för programmering i ISO 646-teckenuppsättningar. |
limits.h |
Innehåller konstanter som definierar heltalsmiljön. | |
locale.h |
Innehåller funktioner och konstanter för lokalisering; se locale. | |
math.h |
Innehåller matematiska funktioner och konstanter. | |
setjmp.h |
Innehåller makrona setjmp och longjmp, som används för hopp mellan funktioner. |
|
signal.h |
Innehåller funktioner och definitioner för att hantera vissa meddelanden i miljön. | |
stdalign.h |
C11 | Innehåller makron för att specificera och testa datajustering (data alignment) i strukturer. |
stdarg.h |
Innehåller funktioner för att hantera ett variabelt antal parametrar till en funktion. | |
stdatomic.h |
C11 | Innehåller defintioner och funktioner för atomiska operationer på data som är delad mellan trådar. |
stdbool.h |
C99 | Innehåller makron för den booleska datatypen. |
stdint.h |
C99 | Innehåller definitioner av olika heltalstyper. |
stddef.h |
Innehåller ett antal standarddefinitioner. | |
stdio.h |
Innehåller standardfunktionerna för läsning och skrivning av data. | |
stdlib.h |
Innehåller ett antal standardfunktioner för bland annat minnesallokering. | |
stdnoreturn.h |
C11 | Innehåller ett makro för att definiera funktioner som inte returnerar alls. |
string.h |
Innehåller funktioner för stränghantering. | |
tgmath.h |
C99 | Innehåller datatypgeneriska matematiska funiktioner. |
threads.h |
C11 | Innehåller funktioner och definitioner för trådning. |
time.h |
Innehåller funktioner för konvertering mellan tids- och datumformat. | |
uchar.h |
C11 | Innehåller typer och funktioner för att hantera Unicode-tecken. |
wchar.h |
NA1 | Innehåller funktioner för hantering av Unicode-tecken och -strängar. |
wctype.h |
NA1 | Innehåller funktioner för att klassificera och konvertera Unicode-tecken. |
[redigera] Programexempel
"Hello, World!" i C:
#include <stdio.h> int main(void) { printf("Hello, world!\n"); return 0; }
Ett program där vi kan titta på givna intervaller av multiplikation av ett givet tal i:
#include <stdio.h> int main (int argc, const char * argv[]) { int raknare, lagsta, hogsta; /* * raknare = En räknare för att hålla koll på vilken rad vi är på vid utskriften. * lagsta = Vårt lägsta värde på i. Med detta värde på i ska utskriften starta. * hogsta = Vårt högsta värde på i. Efter i = n ska utskriften sluta. */ printf("Ange lägsta värdet på i: "); scanf("%i", &lagsta); /* Vad ska lägsta värdet på i vara? */ printf("Ange högsta värdet på i: "); scanf("%i", &hogsta); /* Vad ska största värdet på i vara? */ printf("\n i i*i i*i*i\n" "============ ============ ============\n"); for (raknare = lagsta; raknare <= hogsta; raknare++) { /* Upprepning av utskriften. */ printf("%12i ", raknare); /* Utmatning av i^1. */ printf("%12i ", raknare*raknare); /* Utmatning av i^2. */ printf("%12i\n", raknare*raknare*raknare); /* Utmatning av i^3. */ } return 0; /* Allt OK. Avslutar programmet. */ }
Samma program som ovan, men där vi istället anropar funktionerna kvad() och kub() för att räkna ut i^2 och i^3:
#include <stdio.h> int kvad(int x) { /* Kvadrerar det värde som funktionen matas med. */ return (x * x); } int kub(int x) { /* Kuberar det värde som funktionen matas med. */ return (x * x * x); } int main (int argc, const char * argv[]) { int raknare, lagsta, hogsta, kvadrat, kubik; /* * raknare = En räknare för att hålla koll på vilken rad vi är på vid utskriften. * lagsta = Vårt lägsta värde på i. Med detta värde på i ska utskriften starta. * hogsta = Vårt högsta värde på i. Efter i = n ska utskriften sluta. */ printf("Ange lägsta värdet på i: "); scanf("%i", &lagsta); /* Vad ska lägsta värdet på i vara? */ printf("Ange högsta värdet på i: "); scanf("%i", &hogsta); /* Vad ska största värdet på i vara? */ printf("\n i i*i i*i*i\n" "============ ============ ============\n"); for (raknare = lagsta; raknare <= hogsta; raknare++) { /* Uprepning av utskriften. */ printf("%12i ", raknare); /* Utmatning av i^1. */ kvadrat = kvad(raknare); printf("%12i ", kvadrat); /* Utmatning av i^2. */ kubik = kub(raknare); printf("%12i\n", kubik); /* Utmatning av i^3. */ } return 0; /* Allt OK. Avslutar programmet. */ }
Ett program som matar ut tal (1 till 10) uttryckt i kvadrat och kubik och visar högerjusterat.
#include <stdio.h> int main(int argc, char *argv[]) { int i; for(i = 1; i <= 10; i++) printf("%8d %8d %8d\n", i, i*i, i*i*i); return 0; }
[redigera] Se även
[redigera] Referenser
- ^ ”Programming Language Popularity”. 2009. http://www.langpop.com/. Läst 16 januari 2009.
- ^ ”TIOBE Programming Community Index”. 2009. http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html.
- ^ Bilting, Ulf; Skansholm Jan (1990). Vägen till C. Lund: Studentlitteratur. ISBN 91-44-26732-0
- ^ Kernighan, Brian W.; Dennis M. Ritchie (1978). The C Programming Language. Englewood Cliffs, NJ: Prentice Hall. ISBN 0-13-110163-3 The first widely available book on the C programming language.
- ^ ”Standards”. The C Book. GBdirect Ltd. 1991. http://publications.gbdirect.co.uk/c_book/preface/standards.html. Läst 24 april 2011.
- ^ ”IBM C for AIX, V6.0 Now Supports the C99 Standard”. IBM. 2 juli 2002. http://www-01.ibm.com/common/ssi/cgi-bin/ssialias?infotype=an&subtype=ca&supplier=897&appname=IBMLinkRedirect&letternum=ENUS202-161. Läst 2 september 2011.
[redigera] Externa länkar
- ANSI
- Programmering i ANSI-C på Wikibooks