
			
			    LAGRINGSKLASSER
			

Alla variabler och funktioner i C har tv egenskaper, lagringsklass och typ.
Vi har hittills ltit bli att behandla lagringsklasserna och verlmnat detta
problemet t kompilatorn. Det finns fyra lagringsklasser:

 	auto

 	extern

 	register

 	static

Variabler som deklareras inom en funktions huvuddel blir automatiskt automa-
tiska, det vill sga att om de inte frses med direktiv om lagringsklass s
blir de av klassen auto. En automatisk variabel r bara knd inom det block
dr den har deklarerats. S snart man har hamnat utanfr klamrarna  vet man
inget om blockets automatiska variabler. Av den orsaken r automatiska vari-
abler lokala. S snart programkrningen hamnar inom ett block reserveras det 
minne fr blockets automatiska variabler, och inom blocket r de definierade
och anvndbara. Men s snart man lmnar blocket igen frsvinner deras vrden.
ven om man senare kommer tillbaka till samma block s uppstr varlablerna p
nytt, men deras tidigare vrden r oknda. Nr auto-variabler definieras bru-
kar man utelmna nyckelordet auto, det anvnds bara om man srskilt vill po-
ngtera lagringsklassen. 

Om man vill att en variabel ska vara knd fr flera funktioner eller block s
deklarerar man dem som externa och placerar deklarationen utanfr alla block
och funktioner. Oftast placerar man sdana fre main och frsker samla alla
av samma typ p ett stlle. Nyckelordet extern behver inte skrivas ut, det 
r platsen fr deklarationen som r huvudsaken. Dremot, om en funktion ska 
anvnda en extern variabel s mste den deklareras inuti funktionen med ordet
extern, annars kommer kompilatorn att lgga upp en ny, automatisk variabel 
med samma namn och funktionen fr aldrig se den externa variabeln. En extern
variabel behller alltid sitt vrde ven ver block- och funktionsgrnser och 
den frsvinner aldrig. De utgr allts en enkel mekanism fr att transportera
vrden mellan funktioner. Ett anat anvndningsomrde fr ordet extern r att
tala om fr kompilatorn och lnkaren att definitionen av variabeln finns i en
annan fil. P det sttet gr det att kompilera ett program i delar fr att 
till slut lnka samman dem. En viss frsiktighet rekommenderas med att anvn-
da externa variabler fr att mata in vrden i funktioner. Att anvnda argu-
ment r oftast en bttre metod eftersom det ger en bttre modulstruktur t
programmet. Dessutom kan det vara riskabelt att ndra en extern variabels 
vrde inom en funktion. Hr br man anvnda argument-returnmetoden.

Lagringsklassen register r ett stt att snllt be om att variabeln ska pla-
ceras i ett av processorns register. Eftersom det inte precis finns ngot 
verfld av register i en 68000, och mnga r upptagna av systemet s r det
inte alls skert att man fr lna ett, och gr det inte s blir variabeln au-
tomatisk i stllet. En typisk kandidat till registervariabel r en rknare i
en slinga, srskilt om slingan r liten men ska genomlpas mnga gnger. Se 
till att deklarera en registervariabel s nra stllet dr den anvnds som 
det gr, s r chansen strre att det finns lediga register, och dessutom 
blockeras inte ngot register i ondan. S snart programmet lmnar blocket 
frigrs registret igen. Kom ihg att lagringsklassen register bara kan bli 
ett frslag till kompilatorn, den avgr sjlv om det r mjligt. Kompilatorn
r dock gjord fr att vara s tillmtesgende som mjligt mot anvndaren.  

Lagringsklassen static har tv viktiga anvndningsomrden. Det mest uppenbara
r att se till s att en lokal variabel behller sitt vrde mellan tv besk
i ett och samma block. En automatisk variabel tappar ju vrdet s snart man 
lmnar dess block och mste initieras igen vid nsta besk.  Det andra r ett
stt att dlja en annars tillgnglig extern variabel. Denna deklareras d som
static external. Vid frsta pseendet kan den klassen verka ondig, en extern
variabel behller ju alltid sitt vrde nd. Men skillnaden r att den sta-
tiska varianten inte r tillgnglig fr funktioner och block som str fre 
variabeldeklarationen. Deras rckvidd r bara den del av kllkodsfilen som 
str efter deklarationen. Vi kan allts anvnda en sdan variabel inom en fa-
milj av funktioner utan att andra kan pverka den. Slutligen kan man dekla-
rera funktioner som static. En sdan r bara tilgnglig inom den fil dr den
har definierats. Man kan allts anvnda sdana fritt inom filen och aldrig 
riskera att anropa dem utifrn av misstag.



			   FRPROCESSORN 


Vi har redan tidigare sett p ett par av frprocessorns instruktioner, #de-
fine och #include. Det finns ytterligare ett antal, #undef, #if, #ifdef,
#ifndef, #else, #endif. Knnetecknet fr en frprocessorinstruktion r att
den inleds med tecknet #. En sdan instruktion fr placeras var som helst i 
kllkodsfilen, men den gller d bara frn och med den plats dr den str och
till slutet av filen. De tv instruktionerna #include och #define r de i 
srklass mest anvnda till frprocessorn. Ovan konstaterade vi att #define 
anvnds fr att gra en s kallad makroersttning i ett program, genom att
man definierar tv strngar, den frsta kallad makron, skriven med stora bok-
stver och utan mellanslag, den andra den strng som senare kommer att er-
stta makron nstan verallt i programmet. Med nstan verallt menas att 
makroersttningen inte sker om makron str inom citationstecken. Men #define
r mer anvndbar n s. Eftersom det gr att anvnda argument tillsammans med
#define kan man konstruera ngot som ser ut som en funktion:

		#define rewind(fp) fseek(fp,0L,0)

Detta exempel kommer ur headerfilen stdio.h och r ett stt att gra en funk-
tion som "terspolar" en fil, allts placerar positionspekaren i brjan av 
filen igen. Eftersom funktionen rewind inte finns i standardbiblioteket gr
man den av fseek(). Argumentet fp r en pekare som pekar p filen som sdan.
Nr frprocessorn trffar p denna instruktion brjar den leta efter alla 
frekomster av strngen rewind(...) i kllkoden. Nr den hittar en bytes den
ut mot fseek(...). Men sen kommer det listiga, det som str som argument till
rewind(..) stts in som argument i fseek, p den plats dr fp str. Vi erst-
ter allts frst makrofunktionens namn och sedan dess argument, p samma stt
som en funktions formella argument byts ut mot det verkliga vid anropet. Det 
finns dock en viktig skillnad, funktionsanropet verfr vrdet av argumentet 
vid programkrningen, medan makron verfr argumentstrngen och det redan 
fre kompileringen. En konsekvens av detta r att man mste tnka efter noga
innan man definierar sin makro s att den verkligen fungerar som man vill. 
Ett vanligt problem uppstr nr man anvnder upprkningsoperatorn ++ i argu-
mentet till en makro. En funktion berknar frst vrdet av argumentet och
verfr det, medan makron verfr argumentstrngen, och varje gng som den
anvnds i makrofunktionen, kommer upprkningen att ske. Enda sttet att klara
detta bekymmer r att aldrig anropa en makro med ett argument som kommer att
upp- eller nerrknas i makron. Vi ser p ett exempel som berknar kvadrater:

 	#define SQUARE(x) ((x)*(x))

Lgg mrke till alla parenteserna. De kommer sig av att man i C inte r ga-
ranterad att ett uttryck berknas i ngon viss ordning. Om vi utelmnar alla
parenteserna och anropar makron med argumentet 5+z, s kommer makroutbytet 
att resultera i:

 	5+z*5+z 

Men det vi tnkte oss var ju:

 	(5+z)*(5+z) 

Se grna upp med en detalj till, makronamnet slutar ju vid det frsta blank-
tecknet, s om du lmnar ett blanktecken fre parentesen kring argumentet, s
kommer preprocessorn att tro att argumentet hr till strngen som makron ska
bytas mot:

 	#define SQUARE (x) ((x)*(x))

Ett frsk att berkna kvadraten p 5 med denna makrodefinition resulterar i
att makron SQUARE byts ut mot (x) ((x)*(x)), allts blir SQUARE(5) utbytt
mot (x) ((x)*(x)) (5) eftersom det vi tror r argumentet, (5), av frproces-
sorn inte uppfattas som ngot som hr till makron alls, och fljaktligen str
det kvar som tidigare.

Varfr ska man nu anvnda makros nr det r s mycket problem med dem? En 
makro skapar en linjr kod, det vill sga en kod som r fri frn hopp till
funktioner med all den extra tid som det tar, men  andra sidan kommer 
makron att finnas med i koden varje gng den anvnds, medan en funktion bara
behver finnas i ett exemplar. Makromodellen leder allts till lngre kod men
snabbare krning, medan funktionsvarianten blir mer kompakt och lngsammare.
Tnk efter och vlj sjlv, det normala r att makros anvnds fr mycket enkla
funktioner dr tiden fr ett funktionsanrop blir stor jmfrt med tiden fr 
utfrandet av sjlva funktionskoden. 

En frdel med makroinstruktioner r att man inte behver tnka p typen p
argumentet eftersom makron inte arbetar med vrden utan bara teckenstrngar.
 andra sidan kan det ge problem av andra slag om man skickar fel sorts argu-
ment till en funktion, resultatet blir kanske inte vad man har vntat sig, 
och ngon varning fr man inte om "type mismatch".

Om vi har definierat en konstant eller en makro som vi inte lngre vill ska 
glla s r det bara att ge frprocessorinstruktionen #undef fljd av namnet
p det vi definierat.

Instruktionen #include har som vi tidigare konstaterade till uppgift att ta 
in filer utifrn i programmet. Dels anvnder man de headerfiler som fljer 
med kompilatorn, dels kan man skapa egna filer med definitioner och funktio-
ner och ta in dem i koden med #include. En fil som tas in med #include, kan 
sjlv innehlla ett antal #includeinstruktioner. Det finns en grns fr hur
mnga niver detta fr hlla p, men i Lattice C till exempel tolereras 10
niver, och det br rcka till fr de flesta.

Frprocessorn har ocks ngra villkorsinstruktioner, #if, #ifdef, #ifndef,
#else, #endif. Med dessa kan man skapa kllkodsfiler som enkelt kan kompi-
leras p olika stt. Ett anvndningsomrde kan vara att skriva program som
kan kompileras fr krning p olika system, ett annat kan vara att skriva in
kod fr avlusningsndaml med villkorsinstruktioner omkring s att det r 
ltt att kompilera programmet utan dem nr det vl fungerar.
