C modules

Identification

Infoforall

Organisation programme C


ATTENTION : cette fiche ne constitue qu'une initiation à la structuration d'un projet en C. Ne la voyez pas comme une finalité mais comme une introduction. Certaines notions sont parfois présentées de façon simplifiées de façon à vous permettre de prendre assez facilement la main. Vous verrez plus tard comme faire cela de façon encore plus ordonnée et structurée.

Cette page vous explique comment organiser votre projet en répartissant vos codes entre plusieurs fichiers puis comment compiler l'ensemble.

Vous allez répartir votre code dans différents modules, chaque module étant défini à travers deux fichiers :

  1. Les fichiers d'en-tête (header) d'extension .h qui contiendront les informations publiques : ce qui doit être visible de l'exérieur pour parvenir à utiliser votre module :
    • Les prototypes et documentations des fonctions (publiques)
    • Les déclarations de structures (publiques)
    • Les typedef
    • Les constantes / macros
  2. Les fichiers sources d'extension .c qui contiendront la grande majorité de votre code dont vos fonctions privées : ces fichiers contiennent les codes effectifs de vos fonctions.
    • Le code des fonctions publiques et privées
    • Les fonctions privées (avec static)
    • Les détails d’implémentation
    • Les variables internes
Lorsque vous voulez créer du code qui soit réutilisable dans un autre cadre que votre projet, il ne faut pas le placer dans votre main.c mais dans deux autres fichiers d'extension .c et .h, disons personne.c.

Prenons un exemple simple avec un module contenant de quoi définir une Personne :
MONPROJET/ (répertoire / dossier) ├── personne.h ├── personne.c └── main.c

Cliquer pour obtenir le détail des différents fichiers.

Fichier personne.h (avec et sans documentation)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
#ifndef PERSONNE_H // SI la macro n'est pas encore définie ALORS #define PERSONNE_H #include <stddef.h> // pour NULL #define NOM_MAX 100 // taille maximale du nom (modifiable) typedef struct { char nom[NOM_MAX]; // nom stocké directement dans la structure int age; } Personne; int initialiser_personne(Personne* p, const char* nom, int age); const char* get_name(const Personne* p); int get_age(const Personne* p); #endif // FIN du SI
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
/* personne.h */ #ifndef PERSONNE_H // Si la macro n'est pas encore définie #define PERSONNE_H #include <stddef.h> // pour NULL #define NOM_MAX 100 // taille maximale du nom (modifiable) /** * Structure représentant une personne */ typedef struct { char nom[NOM_MAX]; // nom stocké directement dans la structure int age; } Personne; /** * @brief : Initialise une personne. * * @param p : pointeur vers la personne * @param nom : nom de la personne (copié dans le tableau) * @param age : âge de la personne * @return 0 si OK, -1 en cas d'erreur */ int initialiser_personne(Personne* p, const char* nom, int age); /** * @brief : Renvoie le nom de la personne. * * @param p : pointeur vers la personne * @return le nom (chaîne de caractères); NULL si erreur */ const char* get_name(const Personne* p); /** * @brief : Renvoie l’age de la personne. * * @param p : pointeur vers la personne * @return l’age, -1 si erreur */ int get_age(const Personne* p); #endif

Traduction en français des différentes lignes :

  • Ligne 2 : SI la macro PERSONNE_H n'a pas encore été définie alors réalise les lignes 3 à 38.
  • Cela permet d'utiliser include sans se soucier de savoir si son code a déjà été ramené dans le code source : si ce n'est pas le cas, on le ramène et on crée la macro pour s'en souvenir, sinon on ne fait rien puisqu'il n'y a rien sous le endif.

  • Ligne 38 : Fin du SI
  • Ligne 3 : Directive signifiant "crée une macro PERSONNE_H".
  • Lignes 10-13 : Création du type Personne qui est une STRUCTURE PUBLIQUE puisqu'on fournit sa structure exacte.
  • Lignes 15-.. : On fournit PROTOTYPES et DOCUMENTATIONS de fonctions.

Notez que j'intégre ici des versions d'accesseurs qui gèrent les éventuels envois de personnes mal configurés.

Autre technique possible : on peut choisir de ne rien tester MAIS de préciser comme PRECONDITIONS : personne valide. C'est alors à la personne qui appelle votre fonction de faire le test AVANT l'appel.

Fichier personne.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
#include <string.h> #include <stdio.h> #include "personne.h" int initialiser_personne(Personne* p, const char* nom, int age) { if (!p || !nom) return -1; strncpy(p->nom, nom, NOM_MAX - 1); p->nom[NOM_MAX - 1] = '\0'; p->age = age; return 0; } const char* get_name(const Personne* p) { if (!p) return NULL; return p->nom; } int get_age(const Personne* p) { if (!p) return -1; return p->age; }

Notez la différence de syntaxe pour la directive include entre les modules personnels et les modules natifs.

La directive demandant de recopier personne.h permet de récupérer la structure ET de vérifier que les déclarations anticipées (prototypes) correspondent bien aux prototypes des déclarations.

Fichier main.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
#include <stdio.h> #include "personne.h" int main(void) { Personne pers; if (initialiser_personne(&pers, "Alice", 25)) { printf("Erreur d'initialisation\n"); return 1; } printf("Nom : %s\n", get_name(&pers)); printf("Age : %d\n", get_age(&pers)); printf("Appuyez sur Entrée pour quitter..."); getchar(); return 0; }

La compilation est ensuite réalisée de cette façon :

1
gcc main.c personne.c -o programme
  • On lance un appel au programme gcc
  • en lui donnant en arguments d'appel les différents fichiers .c à lier,
  • l'option -o permet d'indiquer le nom qu'on veut donner à l'exécutable.

Il ne reste alors plus qu'à lancer votre exécutable (attention, sous Windows, le nom programme aura certainement été transformé en programme.exe) :

1 2 3 4
./programme Nom : Alice Age : 25 Appuyez sur Entrée pour quitter..

RAPPEL sur les commandes en ligne de code :

  • Trouver le répertoire actuel : .
  • Trouver le répertoire parent : ..
  • Se déplacer : cd chemin_a_suivre (ainsi cd ../.. veut dire de remonter deux fois dans l'arborescence.
  • Voir le contenu du répertoire courant : ls ou ls -al.

Article publié le 01 03 2026
Dernière modification : 01 03 2026
Auteur : ows. h.