Historically, modularity emerged as a way to divide large projects into independent logical parts to improve readability, code reuse, and responsibility sharing among developers. In C, modularity is implemented at the file level — source (.c) and header (.h).
The problem that programmers face is how to organize interaction between parts of the code, avoid duplication of definitions, maintain encapsulation, and simplify compilation.
The solution is to use the separation of interface and implementation:
Example structure of modular 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; }
Key features:
Can you define a variable with extern in a header file and safely use it in multiple modules?
No! Global variables should only be defined in one .c file, and only declared through extern in headers. Otherwise, linker errors will occur due to "multiple definition".
Is it mandatory to include each header file through #include only once?
It is necessary to wrap each .h file with guard macros (#ifndef/#define/#endif), otherwise, conflicts in declarations and compilation errors will arise due to multiple inclusions.
Is it possible to achieve pure encapsulation of private data in a structure (opaque pointer) in C?
Yes. The so-called "opaque pointer" allows hiding the structure details from the user:
// mystruct.h typedef struct MyStruct MyStruct; MyStruct* create(void); void destroy(MyStruct*); // mystruct.c struct MyStruct { int a; };
All logic is implemented in one long .c file, code is repeated, global variables overlap, leading to linker errors.
Pros:
Cons:
Code is decomposed into modules, include guards are used, private data is hidden via opaque pointers.
Pros:
Cons: