Historisch gezien is modulariteit ontstaan als een manier om grote projecten op te splitsen in onafhankelijke logische delen voor betere leesbaarheid, herbruikbaarheid van code en het verdelen van verantwoordelijkheden tussen ontwikkelaars. In C wordt modulariteit gerealiseerd op bestandsniveau — bronbestanden (.c) en headerbestanden (.h).
Een probleem waarmee programmeurs worden geconfronteerd: hoe de interactie tussen verschillende delen van de code te organiseren, duplicatie van definities te vermijden, de encapsulatie niet te schenden en de assemblage te vereenvoudigen.
Oplossing — gebruik maken van scheiding van interface en implementatie:
Voorbeeld van de structuur van modulaire code:
// mymath.h #ifndef MYMATH_H #define MYMATH_H int add(int, int); #endif // mymath.c #include "mymath.h" int add(int a, int b) { return a + b; } // main.c #include "mymath.h" #include <stdio.h> int main() { printf("%d\n", add(3, 4)); return 0; }
Belangrijke kenmerken:
Kan een variabele met extern in een headerbestand worden gedefinieerd en veilig in meerdere modules worden gebruikt?
Nee! Globale variabelen moeten alleen in één .c-bestand worden gedefinieerd, en in headerbestanden moeten ze alleen worden gedeclareerd via extern. Anders ontstaan er koppelingsfouten door "multiple definition".
Moet elk headerbestand via #include maar één keer worden opgenomen?
Ja, elk .h-bestand moet worden omhuld met wachters (#ifndef/#define/#endif), anders ontstaan er conflicten bij meerdere insluitingen en compilatiefouten.
Kan een pure encapsulatie van de private gegevens van een structuur (opaque pointer) in C worden gerealiseerd?
Ja. De zogenaamde "opaque pointer" maakt het mogelijk om de details van de structuur voor de gebruiker te verbergen:
// mystruct.h typedef struct MyStruct MyStruct; MyStruct* create(void); void destroy(MyStruct*); // mystruct.c struct MyStruct { int a; };
Alle logica is geïmplementeerd in één lange .c-bestand, code herhaalt zich, globale variabelen overlappen, er ontstaan koppelingsfouten.
Voordelen:
Nadelen:
De code is gedecoupeerd in modules, include guards worden gebruikt, private data is afgeschermd via opaque pointer.
Voordelen:
Nadelen: