Les 5
Functies en header-bestanden
Prototypes, header guards, meerdere bronbestanden en pass-by-value.
🎯 Na deze les kun je
- functies met prototypes declareren en definiëren
- een eigen module maken met een .h- en een .c-bestand
- header guards gebruiken
- uitleggen wat pass-by-value betekent
Functies ken je: een stuk code met een naam, parameters en een returnwaarde. In C komt daar één ding bij: de compiler leest je bestand van boven naar beneden en wil een functie kennen voordat je haar aanroept. Daarvoor bestaan prototypes en header-bestanden. Daarmee kun je je programma ook over meerdere bestanden verdelen.
Een functie in C
#include <stdio.h>
double met_btw(double bedrag, double percentage) {
return bedrag * (1.0 + percentage / 100.0);
}
int main(void) {
printf("%.2f\n", met_btw(10.0, 21.0));
return 0;
}
Vóór de naam staat het returntype, en elke parameter heeft een type. Een functie die niets teruggeeft heeft returntype void.
Prototypes
Zet je met_btw onder main, dan kent de compiler haar nog niet op het moment van de aanroep. Oplossing: een prototype (declaratie) bovenaan:
#include <stdio.h>
double met_btw(double bedrag, double percentage); /* prototype */
int main(void) {
printf("%.2f\n", met_btw(10.0, 9.0));
return 0;
}
double met_btw(double bedrag, double percentage) { /* definitie */
return bedrag * (1.0 + percentage / 100.0);
}
Een declaratie zegt "deze functie bestaat, met deze typen". Een definitie bevat de code. Je mag iets vaak declareren, maar maar één keer definiëren.
Een eigen module: .h en .c
Prototypes die je in meerdere bestanden nodig hebt, zet je in een header (.h). De code komt in een .c-bestand.
btw.h:
#ifndef BTW_H
#define BTW_H
double met_btw(double bedrag, double percentage);
double btw_bedrag(double bedrag, double percentage);
#endif
btw.c:
#include "btw.h"
double met_btw(double bedrag, double percentage) {
return bedrag + btw_bedrag(bedrag, percentage);
}
double btw_bedrag(double bedrag, double percentage) {
return bedrag * percentage / 100.0;
}
main.c:
#include <stdio.h>
#include "btw.h"
int main(void) {
printf("Btw op 50 euro: %.2f\n", btw_bedrag(50.0, 21.0));
return 0;
}
Compileer en link beide bronbestanden:
gcc -Wall -Wextra -c btw.c # → btw.o
gcc -Wall -Wextra -c main.c # → main.o
gcc btw.o main.o -o kassa # linken
of in één keer: gcc -Wall -Wextra btw.c main.c -o kassa. Header-bestanden geef je niet mee aan gcc; die worden via #include binnengehaald.
#include <...> zoekt in de systeemmappen, #include "..." eerst in de map van je eigen bestand.
Header guards
#include plakt de header letterlijk in je bestand. Wordt dezelfde header twee keer ingevoegd (bijvoorbeeld via een andere header), dan kun je dubbele definities krijgen. De drie regels #ifndef BTW_H / #define BTW_H / #endif zorgen dat de inhoud maar één keer meetelt. Veel compilers kennen ook #pragma once, maar dat is geen officiële standaard.
Pass-by-value
Voorspel de uitvoer:
#include <stdio.h>
void verdubbel(int getal) {
getal = getal * 2;
}
int main(void) {
int x = 5;
verdubbel(x);
printf("%d\n", x);
return 0;
}
Het antwoord is 5. C geeft argumenten altijd by value door: de functie krijgt een kopie. Wil je dat een functie de variabele van de aanroeper wijzigt, dan heb je een pointer nodig (les 6), of je geeft de nieuwe waarde terug: x = verdubbel(x);.
Typische fouten
implicit declaration of function: je roept een functie aan zonder prototype of zonder de header te includen.multiple definition of(linker): je hebt een functiedefinitie in een header gezet die door twee.c-bestanden wordt geïnclude. In headers horen alleen declaraties.undefined reference: je vergatbtw.cmee te compileren.
Oefeningen
- Voeg aan de btw-module een functie
double zonder_btw(double bedrag_incl, double percentage)toe en test haar met 121 euro bij 21%. - Waarom levert een header zonder guards die alleen prototypes bevat meestal geen fout op, maar één met een
struct-definitie wel? - Schrijf
int max3(int a, int b, int c)met een prototype bovenmainen de definitie eronder.
Modelantwoord
return bedrag_incl / (1.0 + percentage / 100.0);inbtw.cen het prototype inbtw.h. Resultaat:100.00.- Een declaratie mag vaker voorkomen, een definitie niet. Een
struct-definitie die twee keer in hetzelfde bestand belandt geeftredefinition of 'struct ...'. - Een mogelijke uitwerking:
#include <stdio.h>
int max3(int a, int b, int c);
int main(void) {
printf("%d\n", max3(4, 9, 2));
return 0;
}
int max3(int a, int b, int c) {
int m = a;
if (b > m) m = b;
if (c > m) m = c;
return m;
}
Lab: btw-functies in een eigen module
- Maak
btw.h(met header guard) enbtw.cmetmet_btw,btw_bedragenzonder_btw. - Laat
main.ceen kassabon met drie producten afdrukken: bedrag excl., btw en incl. - Bouw met
gcc -Wall -Wextra -Werror btw.c main.c -o kassa. beetje check c-cpp-les5
Samenvatting
- Een functie moet gedeclareerd zijn vóór de aanroep: via een prototype of een header.
- Een module =
.h(declaraties, met header guard) +.c(definities). - Je compileert alle
.c-bestanden en linkt ze samen; headers geef je niet mee. - C kopieert argumenten (pass-by-value).
Volgende les: pointers, waarmee een functie wél de variabele van de aanroeper kan wijzigen.
Lab
Btw-functies in een eigen module
🔒 Het live lab hoort bij de volledige cursus. Met één aankoop (€ 29,00, eenmalig) krijg je alle lessen, de live labs en het certificaat. Geen abonnement. Je kunt dit lab altijd gratis lokaal met Docker doen.
💻 Lokaal met Docker. Start de lab-container met (geeft de opdracht een eigen startcommando, gebruik dan dat):
$ docker run -it --rm -e BEETJE_COURSE=c-cpp -e BEETJE_LESSON=5 registry.wizg.it/webhosting/beetjecoderen-web:lab-c-latest
$ docker build -t registry.wizg.it/webhosting/beetjecoderen-web:lab-c-latest -f c.Dockerfile https://beetjecoderen.nl/labs/lab-images.tar.gz
Klaar? Controleer je werk met:
$ beetje check c-cpp-les5
📝 Quiz: functies en header-bestanden
Dit was de laatste gratis les
Je hebt les 1–5 van Een beetje C & C++ gratis gevolgd. Wil je verder? Met één aankoop (€ 29,00, eenmalig) krijg je de overige 30 lessen, de live labs en het certificaat. Geen abonnement.