|
Een inleiding tot C
Inleiding
In dit hoofdstuk worden afspraken gemaakt over de wijze van
naamgeven aan programma's, #include bestanden, funkties,
constanten, variabelen en pointers.
Verder wordt een schema gegeven voor programma indeling. Ook
wordt aandacht besteed aan de opmaak van de tekst. Tenslotte
wordt aangegeven hoe in C met commentaar kan worden gewerkt.
Naamgeving Programma's
De naam van programma's moeten voldoen aan de eisen die MS-DOS
stelt. De extensie is C voor de programma bestanden. Voor de
#include bestanden geldt de extensie H.
Funkties
Eigen funktie namen beginnen met een hoofdletter en bestaan
verder uit een combinatie van kleine- en hoofdletters, zoals
bijvoorbeeld MaakSamenvatting ().
of SlaGegevensOp () Funktie
namen moeten zoveel mogelijk zelfverklarend zijn en uit een
werkwoord + zelfstandig naamwoord bestaan. De maximum naamlengte
is 32 posities. Gebruik geen namen als A of B
Laat geen code voor het type van de funktie aan de naam vooraf
gaan, omdat dit verwarring met een variabele naam kan opleveren.
Er is een uitzondering op de regel, de funktie main (). Deze
moet :hp3.altijd:ehp3. in kleine letters worden geschreven. Voor C is
dit het zogenaamde entry-point, de plaats waar het programma met de
uitvoering zal beginnen.
Voeg een spatie tussen de funktie naam en de openingshaak en
scheid de eventuele parameters met een komma en een spatie, zoals
bijvoorbeeld DrukTekstAf (10, 40, "voorbeeld");.
Constanten
Probeer van meet af aan constanten te benomen met een
zelfverklarende naam in plaats van een waarde.
Dit maakt achteraf wijzigen eenvoudiger.
Constante-namen zoals ZEROzijn ongelukkig
gekozen, in geval de waarde ervan veranderd in bijvoorbeeld 10.
In plaats daarvan kan beter voor ONDERGRENS gekozen worden.
Als er constanten zijn die op enigerlei wijze logisch gegroepeerd
kunnen worden, geef die dan een groepcode vooraf. Stel dat je
programma een aantal foutcodes kan afgegeven, dan zou je die
bijvoorbeeld de namen FC_GOED, FC_FOUT
en FC_NIET_GEVONDEN kunnen geven.
Constanten worden een naam gegeven met behulp van de #define
opdracht. Het voorbeeld van boven zou er uit kunnen zien als:
#define FC_GOED 0 /* Geen fout opgetreden */
#define FC_NIET_GEVONDEN 10 /* Geen gegevens */
#define FC_FOUT 99 /* Fout opgetreden */
Variabelen
Variabelen moeten een zelfverklarende naam hebben die uit een
combinatie van hoofd- en kleine letters bestaan. Bij voorkeur
worden ze voorafgegaan door een code die het type aanduidt. De
code moet in kleine letters zijn, de eerste letter van de naam
in hoofdletters en de rest naar keuze. Dit wordt ook wel de
Hungarian Notation genoemd. Voor een overzicht en enkele
voorbeelden wordt verwezen naar Appendix B.
Tabellen
Een tabel is een pointer naar een geheugenblok met een vaste
lengte. Dit geheugenblok bevat een vast aantal elementen van een
basistype. Wanneer het aantal elementen niet vooraf bepaald is,
maar wordt bepaald en toegekend gedurende de loop van een
programma, moet de pointer notatie worden toegepast.
CHAR aszNaam[20][33] /* 20 namen van 32 letters */
SHORT asWaarde[50] /* tabel met 50 tellers */
Pointers
Een pointer in C wordt aangegeven door de naam van de pointer
vooraf te laten gaan van het sterretje (*). Het is gebruikelijk
de naam van de pointer te beginnen met de kleine letter p. Bij
een pointer naar een pointer wordt met twee p's begonnen. Op die
manier is makkelijk in het programma te herkennen dat het om een
pointer variabele gaat. Als een pointer wordt gebruikt wijzend
naar een structuur, dan worden de structuur-leden benaderd met de
-> operator.
pRecord->lSaldo /* benadert saldo veld in record */
Structuren en Unions
De namen van structuren en unions moeten worden onderscheiden van
die van variabelen. Stel dat we een structuur/union willen
toepassen om een record aan te geven. We geven die
structuur/union dan een naam en declareren dan een variabele.
We kunnen ook eerst een eigen type definieren om vervolgens de
variabelen die we declareren van dit (eigen) type te maken.
Er volgt een voorbeeld van rechtstreeks:
union _rec { struct _rec {
SHORT sVeld1; SHORT sVeld1;
SHORT sVeld2; SHORT sVeld2;
SHORT sEnzEnz; SHORT sEnzEnz;
} recBetaling; } recBetaling;
en een voorbeeld via type definitie:
typedef union _rec { typedef struct _rec {
SHORT sVeld1; SHORT sVeld1;
SHORT sVeld2; SHORT sVeld2;
SHORT sEnzEnz; SHORT sEnzEnz;
} REC; } REC;
typedef REC *PREC; typedef *PREC;
REC recBetaling; REC recBetaling;
De structuur/union naam wordt geschreven met kleine letters
voorafgegaan door de onderstreping. De typenaam wordt geschreven
met uitsluitend hoofdletters, waardoor we later bij de declaratie
kunnen herkennen dat het om een eigen type gaat. De
structuur/union naam wordt toegepast in situaties waarbij een
pointer naar de eigen structuur/union wordt gedefinieerd.
Hierdoor ontstaat een recursieve datastructuur, ofwel een lijst.
Taal elementen
De taalelementen van C, de zogenaamde reserved words, worden alle
genoteerd in kleine letters.
Programma indeling
In de nu volgende paragraaf wordt een model aangereikt, volgens
welke C programma's kunnen worden opgebouwd. In dit model worden
de volgende programma bestanden onderscheiden:
- Hoofdprogramma met het main entry-point (.C)
- Subprogramma of funktie (.C)
- Header bestand (.H)
Hoofdprogramma met het main entry-point
Een bestand met daarin het C hoofdprogramma wordt als volgt
ingedeeld:
- Proloog, zijnde een commentaarblok met gegevens over het
programma, parameters, etc.
- Eventueel een Copyright regel in een string variabele
- #define's voor conditional #include setting
- #include's van standaard include bestanden (xxx.h)
- #include's van 'eigen' include bestanden, waarin opgenomen
- type definities en funktie prototype's ("xxx.h")
- Declaratie van globale (external) variabelen
- De main() funktie
- Definitie van funkties, liefst alfabetisch
Subprogramma of funktie
Een bestand met daarin een of meerdere C modules (funkties) wordt
als volgt ingedeeld:
- Proloog voor het hele funktie bestand
- #define's voor conditional #include setting
- #include's van standaard include bestanden ()
- #include's van 'eigen' include bestanden, waarin opgenomen
type definities en funktie prototype's ("xxx.h")
- Declaratie van globale (external) variabelen
- Een korte proloog met een beschrijving van de funktie
- De funktie zelf
- Eventueel een herhaling van 5a en 5b, liefst alfabetisch
Header bestand
De header file wordt als volgt ingedeeld:
- Proloog met commentaarblok voor de hele header-file
- #define's voor benoemen van constanten
- #define's voor definitie van C macros
- Definitie van structuren/unions (typedef)
- Definitie van externe variabelen (static en const)
- Funktie prototypes, liefst alfabetisch
Programma tekst opmaak
Regel lengte
Een regel code, commentaar of code + commentaar moeten bij
voorkeur niet voorbij het zichtbare deel van het scherm worden
ingetikt. Hoewel de meeste, moderne editors dit toestaan, wordt
om reden van portabiliteit aangeraden de regels niet langer te
maken dan 79 tekens. De cursor kan dan nog net op positie 80
staan zonder dat het scherm gaat scrollen.
Als een regel toch langer dan 79 posities wordt, moet die worden
gesplitst over twee of meer regels. Het verdient aanbeveling de
gesplitste regels links uit te lijnen.
Als een aanroep of een declaratie van een functie niet op een
regel past, moeten de delen uitgelijnd worden met de eerste
parameter.
Als een tekst-string moet worden gesplitst, doe dit dan bij een
spatie en gebruik in dat geval een extra paar quotes ("").
Tussenruimte
Laat altijd een blanco regel tussen te onderscheiden programma
delen. Een voorbeeld hiervan is een blanco regel tussen
declaraties en de uitvoerbare code, of blanco regel rondom loops
en blokken code.
In het algemeen moet de programmeur met een flinke dosis eigen
inzicht de plaatsen in een programma opzoeken, waar het gebruik
van blanco regels het programma beter leesbaar zullen maken en
gemakkelijker voor het onderhoud.
Inspringen en uitlijnen
Een linker accolade ({) moet altijd op de regel worden gezet bij
het statement waartoe het behoort. De programmaregels die tot het
blok behoren moeten 2 posities inspringen.
Elke nieuwe linker accolade ({) moet weer 2 posities inspringen,
aldus een niveau van inspringen vormend. Zorg ervoor niet teveel
niveaus van inspringen op te bouwen, anders wordt het programma te
onoverzichtelijk.
De rechter accolade (}) moet op een aparte regel worden gezet en
wel recht onder de statement waartoe het behoort. Aldus wordt een
niveau van inspringen terug gesprongen. Voeg het statement als
commentaar achter de accolade toe. Op deze manier is bij een wat
groter blok precies te achterhalen bij welk statement de rechter
accolade hoort.
Voorbeeld:
if (sInvoer == WORP) {
for (sW=1; sW<6; sW++) {
strcpy (szWorp&lbrk.sW&rbrk., ".");
} /* endfor */
DropField (&Screen, 21, 66);
} else {
DropField (&Screen, 21, 69);
...
DropField (&Scrren, 21, 75);
} /* endif */
Declaraties
Declaraties die buiten de funktie worden gedaan, dus ook buiten
de funktie declaratie, moeten aan de linkerkant beginnen. Elke
variabele moet apart op een enkele regel worden gedeclareerd. Als
er een blok van variabelen wordt gedeclareerd moeten ze worden
uitgelijnd.
Voorbeeld:
PSCREEN pScreen; /* pointer naar scherm structuur */
SHORT sRow; /* cursor positie voor regel */
SHORT sColumn; /* cursor positie voor kolom */
PSZ pszString; /* pointer naar de schermtekst */
Structuur en Union declaraties
Net als bij de programma regels, wordt de mate van inspringen bij
structuren geregeld met linker en rechter accolades. De type
declaratie wordt met twee posities ingesprongen, de variabele
declaratie begint onder de linker accolade ({). De linker
accolade wordt achter de structuur naam op dezelfde regel
geplaatst. Het verdient aanbeveling van een structuur een type
declaratie te maken en daarna ook een pointer naar de structuur
als type te declareren.
De structuur naam wordt gestart met de onderstreping en gevolgd
door kleine letters; de type naam is dan de structuurnaam zonder
de onderstreping in hoofdletters.
Voorbeeld:
typedef struct _screen {
PFIELD pFieldFirst; /* pointer to 1st field */
PFIELD pFieldLast; /* pointer to last field */
SHORT sNrOfFields; /* Nr of fields in list */
SHORT sRows; /* Nr of rows on screen */
SHORT sColumns; /* Nr of cols on screen */
} SCREEN;
typedef SCREEN *PSCREEN; /* ptr to screen struct */
Declaraties binnen functies
De declaratie van de parameters moet in de function header worden
gedaan. Als de parameters niet meer op een regel passen, moeten
ze over meerdere regels worden verspreid. Het beste is een per
regel en keurig inspringen onder de eerste declaratie.
De declaratie van de gebruikte variabelen moeten boven aan de
funktie worden gedaan en op kolom 8 beginnen. Dit biedt de
mogelijkheid om er static of extern
voor te programmeren
(waarover later). Ook hier moet er per regel maar een variabele
worden gedeclareerd.
Voorbeeld 1 (oude compilers):
VOID DropField (pScreen, sRow, sColumn)
PSCREEN pScreen;
SHORT sRow;
SHORT sColumn;
{
PFIELD pField;
return;
} /* End DropField */
Voorbeeld 2 (moderne compilers):
VOID DropField (PSCREEN pScreen, SHORT sRow, SHORT sColumn)
{
PFIELD pField;
return;
} /* End DropField */
Statement specifieke opmaak
Gebruik de volgende opmaak voor het if-else statement:
if (conditie) {
statement(s);
} else {
statement(s);
} /* endif (conditie) */
Gebruik de volgende opmaak voor het if statement:
if (conditie) {
statement(s);
} /* endif (conditie) */
Gebruik de volgende opmaak voor het while statement:
while (conditie) {
statement(s);
} /* endwhile (conditie) */
Gebruik de volgende opmaak voor het do-while statement:
do { /* begindo while (conditie) */
statement(s);
} while (conditie);
Gebruik de volgende opmaak voor het for statement:
for (startvoorwaarde; conditie; stapgrootte) {
statement(s);
} /* endfor (conditie) */
Gebruik de volgende opmaak voor het switch statement:
switch (variabele) {
case 1:
statement(s);
break;
case 2;
statement(s);
break;
case 3:
case 4:
statement(s);
break;
default: /* bij voorkeur */
statement(s);
break; /* naar keuze */
} /* endswitch (variabele) */
Preprocessor statements
Alle preprocessor statements moeten beginnen aan de linkerzijde
met het keyword direct tegen de preprocessor vlag (#). Dit geldt
ook voor #ifdef, #ifndef en #endif statements die een voorwaarde
vormen voor de compiler (conditional compilation).
Om meervoudige declaraties van constanten tegen te gaan wordt het
gebruik van het statement-paar #ifdef / #endif aangeraden.
Richtlijnen voor commentaar
Commentaar moet duidelijk zijn, beschrijvend en tot hulp dienen.
Voor nationale toepassingen moet het commentaar in het Nederlands
gesteld zijn, voor internationale toepassingen moet het
commentaar in het Amerikaans Engels worden opgesteld.
Commentaar in C begint met de /* combinatie en eindigt met de
*/ combinatie. Het zogenaamd nesten van commentaar is, in
verband met overdraagbaarheid van code, NIET toegestaan.
Commentaar blok
Commentaar wordt meestal toegevoegd in blokken. Deze blokken
moeten zoveel mogelijk vierkant lijken en samen met de programma
tekst inspringen.
Voorbeeld van een commentaarblok
/******************************************************************/
/* */
/* Dit is een voorbeeld van een commentaar blok ... */
/* */
/******************************************************************/
Commentaar regel
Commentaar regels worden alleen toegepast als verduidelijking.
Dit commentaar wordt altijd links en rechts uitgelijnd.
Voorbeeld van een commentaarregel
/* Dit is een voorbeeld van een commentaar regel ... */
Toegevoegd commentaar
Commentaar kan ook achter de programma regels worden toegevoegd.
Probeer links uit te lijnen op een vaste (zelf te kiezen) kolom
en rechts met de andere type commentaar regels. Het commentaar
kan worden toegevoegd op meerdere regels indien nodig.
Voorbeeld van toegevoegd commentaar
printf ("Start programma"); /* Debugging informatie */
/* links/rechts uitgelijnd */
Aanvullende opmerkingen
Sommige compilers accepteren ook het zogenaamde One-Line-Comment, de //
combinatie. Alles wat achter deze tekens staat wordt gezien als commentaar.
Wees er echter van bewust dat niet alle compilers dit accepteren, waardoor
het programma niet overdraagbaar is.
|