C-taal voor beginners - hoofdstuk 10

aanbevolen C stijl- en coderingsnormen


[10.1 inleiding] [10.2 bestandsorganisatie] [10.3 bestandsnamen] [10.4 programmabestanden] [10.5 header bestanden] [10.6 commentaar] [10.7 declaraties] [10.8 witruimte] [10.9 compound statements] [10.10 operators] [10.11 tabs] [10.12 conclusie] [10.13 tenslotte]


10.1 inleiding

Dit hoofdstuk bespreekt in het kort de standaardmanier waarop in C bepaalde stijlen en coderingsmethodes toegepast worden. Alhoewel niet verplicht, is het aan te raden deze te volgen wanneer u een programma schrijft. De beste en meest professionele programmeurs kwamen bijeen om deze regels te ontwikkelen. Dit wil zeggen dat een programma dat er gebruik van maakt, er professioneler uitziet en gemakkelijker te begrijpen is. Het doel van dit hoofdstuk is de leesbaarheid verbeteren, het onderhoud verminderen en boven alles de klaarheid van het programma te maximaliseren.

In feite heeft dit weinig te maken met het aanleren van de C-taal, maar ik vond het een onmisbaar concept voor ieder die op een serieuze manier programma's wil schrijven. Denkt of vindt u deze kennis niet nodig te hebben, kan u het hoofdstuk gewoon overslaan.

Opmerking: de voorbeelden uit de cursus zullen niet altijd overeenstemmen met wat ik hier vertel. Op sommige regels maak ik zelf een uitzondering, omdat ik met deze methode vertrouwd was, reeds voordat ik de stijlregels kende.

10.2 bestandsorganisatie

Een bestand bestaat uit verschillende secties die zouden gescheiden moeten worden door verschillende lege regels. Alhoewel er geen maximumlengte voor bronbestanden vastgelegd is, zijn bestanden van meer dan duizend lijnen ingewikkeld om mee te werken. De editor heeft mogelijk niet genoeg tijdelijk geheugen om het bestand te bewerken, compilaties gaan trager, enz... . Vele rijen met asterisks, als commentaar, nemen te veel tijd in beslag om ze te bekijken en worden beter vermeden. Overdrijf nooit met het gebruik van witregels en tabs, zodat een bestand met honderd regels tekst uiteindelijk niet vijfhonderd regels lang is.

10.3 bestandsnamen

Bestandsnamen worden samengesteld uit een basisnaam en een optioneel punt en achtervoegsel (extensie). Het eerste karakter van de naam zou een letter moeten zijn en alle karakters moeten kleine letters of nummers zijn. De basisnaam moet acht of minder karakters breed zijn en de extensie drie of minder karakters. Deze regels worden best toegepast op elk soort bestand.

Sommige compilers en toepassingen vereisen bepaalde extensie conventies voor namen van bestanden:

10.4 programmabestanden

De voorgestelde volgorde voor secties in een programmabestand is als volgt:

  1. Allereerst in het bestand is een proloog die vertelt wat er in het bestand voorkomt. Een omschrijving van het doel van de objecten in het bestand, de externe data declaraties of definities en andere dingen die u graag vermeld. De proloog kan optioneel auteurs, revisieinformatie en referenties bevatten.
  2. De header includeringen volgen dan. Als de #include voor een niet voor de hand liggende reden dient, dan moet dit met een commentaarlijn verklaard worden. In de meeste gevallen worden systeem #include bestanden zoals stdio.h geincludeerd voor gebruikers #include bestanden.
  3. Als volgt komen de #defines die van toepassing zijn op het ganse bestand. Plaats constante macro's voor functie macro's. Dan komen de enums.
  4. Daarna komen de globale (externe) data declaraties, gewoonlijk in de volgorde: extern, niet-statisch, globaal, statisch globaal.
  5. De functies komen als laatste en zouden in een logische volgorde geplaatst moeten worden.

10.5 header bestanden

Header bestanden zijn bestanden die in andere bestanden worden ingevoegd door de compiler, voorafgaand aan de compilatie door de C preprocessor. Sommige, zoals stdio.h, worden gedefinieerd op systeemniveau en moeten geincludeerd worden door elk bestand dat gebruikt maakt van de standaard I/O bibliotheek. Vermijd privé header bestandsnamen die hetzelfde zijn als bibliotheek header bestandsnamen. Het statement

#include "math.h"

zal het standaard math.h dat bij uw compiler zit laden, als het bedoelde niet gevonden wordt in de huidige directory. Indien u dit toch zo wilt, moet u dat met commentaar uitleggen.

10.6 commentaar

"Als code en commentaar het niet met elkaar eens zijn, zijn beide waarschijnlijk fout."-- Norm Schryer

Commentaar in een programma moet omschrijven wat er gebeurt, hoe het gebeurt, wat de parameters betekenen, welke globalen gebruikt worden en aangepast zijn en eventuele beperkingen of problemen. Vermijd commentaar dat duidelijk is uit de code, omdat dit nogal vlug oud wordt. Commentaar dat het niet eens is met de code is van negatieve waarde. Korte commentaar zou van het wat type moeten zijn, zoals "bereken som", i.p.v. het hoe type, zoals "som van de waarden gedeeld door n en vermenigvuldigd met y". C is anders dan Assembleertaal; commentaar op de eerste tien lijnen van een programma dat verteld wat het in het algemeen doet, is meestal meer gebruikelijk dan een commentaarlijn op elke regel om de micrologica te beschrijven.

Gebruik commentaar om "lelijke" code te rechtvaardigen. De uitleg zou moeten zijn dat er iets slechts zal gebeuren als er gewone code gebruikt wordt. Code gewoon sneller maken is niet genoeg; de verbetering moet getoond worden. Leg in het commentaar uit waarom u de ongewone methode gebruikt en waarom het een goede oplossing is.

Commentaar om datastructuren, algorithmen, enz... te beschrijven, zou in blokvorm met het openende /* in kolom 1-2, een * in kolom 2 voor elke lijn met commentaartekst en het sluitende */ in kolom 2-3 moeten staan. Een alternatief is om ** in kolom 1-2 te plaatsen en het sluitende */ ook in 1-2.

/*
 *        Hier staat een blokcommentaar.
 *        De commentaartekst zou tabs en witruimtes moeten gebruiken.
 *        Het openende slash-ster en sluitende ster-slash staan alleen op één lijn.
 */
/*
** Alternatief formaat voor blokcommentaar.
*/

Blokcommentaar binnen een functie is passend en zou op dezelfde positie moeten staan als de code waarover de commentaar gaat. Commentaar dat alleen op een lijn staat zou de tabpositie moeten gebruiken van de volgende code.

do
{
    c = fgets(eenwoord, 100, fp1);
    /* Controleren of het bestand op zijn einde is. */
    if (c != NULL)
        printf("%s", eenwoord);
} while (c != NULL);

Zeer korte commentaar mag op dezelfde lijn staan als de code die ze beschrijven en er zou een zekere witruimte tussen moeten staan. Als er meer dan één commentaar voorkomt in eenzelfde blok code, dan moeten deze op dezelfde tabpositie te staan.

do
{
    c = fgets(eenwoord, 100, fp1);
    if (c != NULL)	/* Controleren of het bestand op zijn einde is. */
        printf("%s", eenwoord);     
} while (c != NULL);			/* Doorgaan totdat c NULL is */

Het is mogelijk dat uw browser dit niet helemaal juist weergeeft, maar de uitleg is duidelijk. U kan de voorbeeldprogramma's bij deze cursus bekijken voor het juiste gebruik van commentaar.

10.7 declaraties

Bij een lange lijst declaraties van hetzelfde type variabele, zoals

char string1[20], string2[50], string3[320], string4[5], string5[10], string6[20];

worden de variabelen beter elk op een lijn geplaatst:

char string1[20],
     string2[50],
     string3[320],
     string4[5],
     string5[10],
     string6[20];

In Europa is deze methode niet echt geliefd. Het is dan ook weinig moeite om het bovenstaande als volgt te declareren en de leesbaarheid te verhogen.

char string1[20];
char string2[50];
char string3[320];
char string4[5];
char string5[10];
char string6[20];

10.8 witruimte

Gebruik verticale en horizontale witruimte overvloedig. Inspringingen moeten de blokstructuur van de code weergeven. Er zouden, bijvoorbeeld, tenminste twee witregels moeten staan tussen het einde van een functie en het commentaar van de volgende.

Een lange rij van conditionele statements kan u beter over afzonderlijke lijnen verdelen:

if(cijfer1 <  cijfer2 && cijfer1 > cijfer3 && cijfer2 > cijfer4) {...

kan u misschien beter schrijven als

if(cijfer1 <  cijfer2 
        && cijfer1 > cijfer3
        && cijfer2 > cijfer4) 
{       ....

Op dezelfde manier kunnen for() loops gescheiden worden over meerdere regels:

for(i = 0, y = 100;
        y < 50;
        i++, y + 2 * x)
{       ....

Andere complexe operaties, zoals degene die de ? : gebruiken, kan u ook best scheiden:

c = (a == b)
            ? d + f(A)
            : f(b) - d;

Het is wel aan te raden om de ? : constructie zoveel mogelijk te vermijden. Sleutelwoorden die gevolgd worden door een expressie tussen ronde haken zouden gevolgd moeten worden door een spatie (behalve de sizeof operator). Blanco's zouden ook na komma's moeten komen in de argumentenlijst om de argumenten visueel beter te kunnen onderscheiden. Macrodefinities met argumenten mogen geen witruimte hebben tussen de naam en het linkerhaakje, anders zal de C preprocessor het niet herkennen.

10.9 compound statements

In deze cursus werden voorwaarden met meer dan één opdracht als volgt gecodeerd:

if(getal == 250)
{
    printf("Het getal is 250\n");
    printf("Dus is het niet 300\n");
}

Dit is de Amerikaanse stijl:

if(getal == 250) {
    
    printf("Het getal is 250\n");
    printf("Dus is het niet 300\n");
}

Als u een heleboel geneste compound statements gebruikt in een programma is de tweede methode niet echt aan te raden. Indien bij een if() else statement één van de twee secties samengesteld is, zouden zowel de if() als else voorwaarde(n) tussen acollades moeten geplaatst worden:

if(getal == 250)
{
    printf("Het getal is 250\n");
}
else
{
    printf("Het getal is dus niet 300\n");
    printf("Ook is het kleiner dan 400\n");
}

De haakjes zijn ook nodig bij if() if() else sequenties, zonder een tweede else. Anders zal de preprocesser dit niet juist coderen voor de uiteindelijke compilatie:

if(getal <= 250)
{
    if(getal == 250)
    {
        printf("Het getal is 250\n");
    } 
}
else
{
    printf("Het getal is kleiner dan 250\n");
}

Dit is een mooi voorbeeld om duidelijk te maken dat de Amerikaanse manier van compound statements nogal ingewikkeld kan werken. Het laatste voorbeeld zou er dan zo uitzien:

if(getal <= 250) {
    if(getal == 250) {
        printf("Het getal is 250\n");
    } 
}
else {
    printf("Het getal is kleiner dan 250\n");
}

10.10 operators

Als u denkt dat een expressie moeilijk te lezen zal zijn, overweeg dan om ze op te breken over verschillende lijnen. De scheiding maken bij de laagste-prioriteit operator naast de onderbreking is het beste. Omdat C een paar vreemde regels heeft, kan u expressies met gemixte operators beter tussen haken plaatsten. Het gebruik van extra ronde haken kan in veel gevallen, bij elk soort expressie fouten vermijden. Overdreven gebruik, echter, maakt een lijn moelijker, aangezien mensen niet goed zijn in het met elkaar vergelijken van linkse en rechtse ronde haken.

10.11 tabs

In de voorbeelden in deze cursus en de programma's die erbij zitten gebruik ik steeds tabs om de leesbaarheid te verhogen. Zolang u op zichzelf werkt is dat geen probleem, maar in groepverband moet u opletten. Een tab kan namelijk op verschillende manieren ingesteld staan, bijvoorbeeld op positie 1, 2, 3, 4 of 8. Zorg voor een goede afspraak omtrent het gebruik van inspringingen. Tabs kunnen ook vreemde resultaten geven bij het afdrukken.

10.12 conclusie

Een standaard werd gepresenteerd voor de C programmeerstijl. De meest belangrijke punten zijn:

10.13 tenslotte

Zoals met elke standaard, moet deze gevolgd worden als het nuttig is. Heeft u problemen met het toepassen van de aanbevelingen in dit hoofdstuk, laat ze dan niet links liggen. Spreek met uw locale guru of ervaren programmeur of leerkracht. De opinies in dit hoofdstuk, of zelfs de ganse gids, zijn niet de opinies van alle auteurs. Sommige schrijvers over de C-taal denken nu éénmaal anders over hoe we zouden moeten programmeren. Alles blijft dan ook een kwestie van eigen smaak.

De belangrijkste regel bij het schrijven van programma's:

"een degelijk programma wordt eerst op papier gezet, daarna op de computer"

Deze lijfspreuk zal ongetwijfeld een hele reeks problemen vermijden. U zal waarschijnlijk denken dat de tussenstap niet nodig is, maar door het programma gewoon in uw compiler beginnen te typen, zal u dingen over het hoofd zien. Op papier ziet iets er meer overzichtelijk uit.

Ik wil u in geen geval verplichten om ook maar iets in deze cursus als gedwongen leerstof te ervaren. Mijn enige doel bij het schrijven ervan was een degelijk, duidelijk en vooral uitgebreid en zo weinig mogelijk ingewikkeld werk te leveren. Denkt u dat ik hierin geslaagd ben en heeft u iets gehad aan deze cursus, dan zou ik het erg op prijs stellen als u me dat laat weten. Indien u constructieve opmerkingen heeft, die kunnen bijdragen tot het verbeteren van deze cursus, dan zou ik ook willen dat u me dat vertelt. Wacht niet met reageren als u vindt dat ik iets op een verkeerde manier uitlegde of fouten gemaakt heb. Een werk bestaande uit zoveel tekst zal ongetwijfeld onregelmatigheden bevatten, zelfs na een paar grondige nazichten. Het meest waarschijnlijk zal u spellingsfouten ontdekken, omdat ik geen spellingstest gebruikte. Daarom werk ik ook in versies. Geleidelijk aan zullen er nieuwere en betere versies verschijnen. Dan begrijpt u ook meteen waarom ik uw inbreng verwelkom. Raadpleeg de inleiding voor informatie om mij te contacteren.


referenties

[Recommended C Style and Coding Standards]

L.W. Cannon - R.A. Elliot - L.W. Kirchhoff - J.H. Miller - J.M. Milner - R.W. Mitze - E.P. Schan - N.O. Whittington - Henry Spencer - David Keppel - Mark Brader

 

Verder naar samenvatting

Terug naar inleiding