Table of Contents
Introduction : Le Probleme des Inclusions Multiples
Dans le developpement en langage C, la gestion des fichiers d’en-tete (headers) constitue un aspect fondamental de l’organisation du code. Un probleme recurrent auquel tout developpeur C est confronte est celui des inclusions multiples : que se passe-t-il lorsqu’un meme fichier d’en-tete est inclus plusieurs fois dans une unite de compilation ?
Imaginons un scenario typique dans un projet C de taille moyenne. Vous avez un fichier types.h qui definit des structures de donnees fondamentales, un fichier utils.h qui inclut types.h, et un fichier main.c qui inclut a la fois types.h et utils.h. Sans mecanisme de protection, le compilateur traiterait deux fois les definitions contenues dans types.h, provoquant des erreurs de redefinition.
// Scenario problematique sans header guards
// types.h
struct Point {
int x;
int y;
};
// utils.h
#include "types.h" // Premiere inclusion de types.h
void print_point(struct Point p);
// main.c
#include "types.h" // Deuxieme inclusion de types.h
#include "utils.h" // Troisieme inclusion indirecte de types.h via utils.h
int main() {
struct Point p = {10, 20};
print_point(p);
return 0;
}
Dans cet exemple, le compilateur verra trois fois la definition de struct Point, ce qui generera une erreur : error: redefinition of 'struct Point'. Ce type d’erreur peut devenir extremement difficile a diagnostiquer dans des projets complexes avec des dizaines de fichiers d’en-tete interconnectes.
Les header guards (gardes d’en-tete) et la directive #pragma once sont les deux solutions principales pour resoudre ce probleme. Ce guide exhaustif vous presentera ces techniques, leurs avantages respectifs, et les meilleures pratiques pour organiser vos fichiers d’en-tete de maniere professionnelle.
Header Guards Traditionnels
Syntaxe #ifndef/#define/#endif
Les header guards constituent la methode standard et portable pour proteger vos fichiers d’en-tete contre les inclusions multiples. Cette technique repose sur le preprocesseur C et utilise trois directives : #ifndef, #define et #endif.
Le principe est simple : a la premiere inclusion du fichier, une macro est definie. Lors des inclusions subsequentes, le preprocesseur detecte que cette macro existe deja et ignore le contenu du fichier.
// Structure de base d'un header guard
#ifndef MONPROJET_MONMODULE_H
#define MONPROJET_MONMODULE_H
// Declarations, definitions de types, prototypes de fonctions
// ...
#endif /* MONPROJET_MONMODULE_H */
Voici un exemple concret avec un fichier d’en-tete pour un module de gestion de listes chainees :
// linked_list.h
#ifndef MYPROJECT_LINKED_LIST_H
#define MYPROJECT_LINKED_LIST_H
#include <stddef.h> // Pour size_t
// Definition de la structure de noeud
typedef struct Node {
void *data;
struct Node *next;
} Node;
// Definition de la structure de liste
typedef struct LinkedList {
Node *head;
Node *tail;
size_t size;
} LinkedList;
// Prototypes des fonctions
LinkedList *list_create(void);
void list_destroy(LinkedList *list);
int list_append(LinkedList *list, void *data);
int list_prepend(LinkedList *list, void *data);
void *list_get(LinkedList *list, size_t index);
size_t list_size(LinkedList *list);
#endif /* MYPROJECT_LINKED_LIST_H */
Conventions de Nommage
Le choix du nom de la macro de garde est crucial pour eviter les collisions. Plusieurs conventions existent, chacune avec ses avantages :
Convention 1 : PROJECT_FILE_H
Cette convention inclut le nom du projet suivi du nom du fichier. Elle est largement utilisee dans les projets open source.
// Pour le fichier buffer.h du projet MyLib
#ifndef MYLIB_BUFFER_H
#define MYLIB_BUFFER_H
// ...
#endif /* MYLIB_BUFFER_H */
Convention 2 : PROJECT_PATH_FILE_H
Pour les projets avec une hierarchie de repertoires, incluez le chemin relatif pour garantir l’unicite.
// Pour le fichier src/core/memory/allocator.h
#ifndef MYPROJECT_CORE_MEMORY_ALLOCATOR_H
#define MYPROJECT_CORE_MEMORY_ALLOCATOR_H
// ...
#endif /* MYPROJECT_CORE_MEMORY_ALLOCATOR_H */
Convention 3 : Avec UUID ou hash
Certains generateurs de code utilisent des identifiants uniques pour garantir absolument l’absence de collision.
// Genere automatiquement
#ifndef HEADER_A7B3C9D2_E4F5_6789_ABCD_EF0123456789
#define HEADER_A7B3C9D2_E4F5_6789_ABCD_EF0123456789
// ...
#endif
Convention 4 : Avec prefixe d’organisation
Les grandes organisations ajoutent souvent un prefixe d’entreprise ou de departement.
// Convention Google
#ifndef GOOGLE_PROTOBUF_MESSAGE_H_
#define GOOGLE_PROTOBUF_MESSAGE_H_
// ...
#endif /* GOOGLE_PROTOBUF_MESSAGE_H_ */
Regles de nommage a respecter
- Utilisez uniquement des majuscules pour la macro
- Remplacez les points et tirets par des underscores
- Evitez les prefixes avec underscore double (
__) ou underscore suivi d’une majuscule (_M), car ils sont reserves par le standard C - Soyez coherent dans tout le projet
- Incluez suffisamment d’information pour garantir l’unicite
// INCORRECT - underscore double reserve
#ifndef __MY_HEADER_H__ // Reserve au compilateur !
#define __MY_HEADER_H__
// INCORRECT - underscore + majuscule reserve
#ifndef _MyHeader_H // Reserve au compilateur !
#define _MyHeader_H
// CORRECT
#ifndef MY_PROJECT_MY_HEADER_H
#define MY_PROJECT_MY_HEADER_H
Placement Correct des Header Guards
Le placement des header guards est egalement important pour maximiser leur efficacite et la lisibilite du code.
Regle 1 : Les guards doivent etre la premiere et derniere chose du fichier
// CORRECT - Les guards englobent tout
#ifndef MYPROJECT_CONFIG_H
#define MYPROJECT_CONFIG_H
// Commentaires de licence
/*
* Copyright (c) 2025 MonProjet
* Tous droits reserves.
*/
#include <stdint.h>
// Contenu du header...
#endif /* MYPROJECT_CONFIG_H */
Regle 2 : Les includes d’autres headers vont APRES le #define
#ifndef MYPROJECT_NETWORK_H
#define MYPROJECT_NETWORK_H
// Les includes vont ici, apres le define
#include <sys/socket.h>
#include <netinet/in.h>
#include "myproject/types.h"
// Declarations...
#endif /* MYPROJECT_NETWORK_H */
Regle 3 : Commentez le #endif pour la lisibilite
#ifndef VERY_LONG_PROJECT_NAME_SUBSYSTEM_MODULE_HEADER_H
#define VERY_LONG_PROJECT_NAME_SUBSYSTEM_MODULE_HEADER_H
// ... beaucoup de code ...
#endif /* VERY_LONG_PROJECT_NAME_SUBSYSTEM_MODULE_HEADER_H */
La Directive #pragma once
Presentation et Syntaxe
La directive #pragma once est une extension non standard du preprocesseur qui offre une alternative plus simple aux header guards traditionnels. Elle indique au compilateur de n’inclure le fichier qu’une seule fois, quelle que soit le nombre de directives #include qui le referencent.
// Syntaxe minimaliste de #pragma once
#pragma once
#include <stdio.h>
typedef struct {
char name[256];
int age;
} Person;
void person_print(const Person *p);
Avantages de #pragma once
1. Simplicite d’utilisation
Pas besoin de choisir un nom de macro unique ou de maintenir la coherence entre les trois directives. Une seule ligne suffit.
// Avec header guards (4 lignes de boilerplate)
#ifndef MYPROJECT_UTILITIES_STRING_HELPER_H
#define MYPROJECT_UTILITIES_STRING_HELPER_H
// contenu
#endif /* MYPROJECT_UTILITIES_STRING_HELPER_H */
// Avec #pragma once (1 ligne)
#pragma once
// contenu
2. Elimination des erreurs de copier-coller
Un probleme courant avec les header guards est le copier-coller d’un fichier a un autre en oubliant de modifier le nom de la macro. #pragma once elimine ce risque.
// Erreur typique apres copier-coller
// fichier: new_module.h (copie de old_module.h)
#ifndef OLD_MODULE_H // Oups ! Mauvais nom !
#define OLD_MODULE_H
// ...
#endif
3. Performance de compilation potentiellement meilleure
Certains compilateurs peuvent optimiser #pragma once en reconnaissant les fichiers deja traites par leur chemin, evitant meme d’ouvrir le fichier une seconde fois. Avec les header guards, le preprocesseur doit toujours ouvrir le fichier pour verifier la macro.
4. Pas de pollution de l’espace de noms des macros
Les header guards ajoutent une macro au preprocesseur qui peut potentiellement entrer en collision avec du code utilisateur. #pragma once ne definit aucune macro.
Inconvenients de #pragma once
1. Non standardise
#pragma once n’est pas defini dans les standards C89, C99, C11, C17 ou C23. Son comportement peut theoriquement varier entre les compilateurs.
2. Problemes avec les liens symboliques et copies de fichiers
Le compilateur identifie les fichiers “identiques” de differentes manieres. Cela peut poser probleme dans certains cas :
# Scenario problematique
ln -s /path/to/header.h /other/path/header.h
# Le compilateur pourrait considerer ces deux chemins comme des fichiers differents
# et inclure le contenu deux fois malgre #pragma once
3. Problemes avec les systemes de build complexes
Dans les environnements avec des montages reseau, des systemes de fichiers virtuels ou des chemins complexes, l’identification des fichiers peut echouer.
4. Comportement inconsistant sur certains compilateurs anciens
Bien que supporte par tous les compilateurs modernes majeurs, certains compilateurs embarques ou specialises peuvent ne pas le supporter.
Support des Compilateurs
| Compilateur | Support #pragma once | Notes |
|---|---|---|
| GCC | Oui (depuis 3.4) | Support complet et optimise |
| Clang | Oui | Support complet |
| MSVC | Oui | Support natif depuis des annees |
| Intel C/C++ | Oui | Support complet |
| ARM Compiler | Oui | Depuis armcc 5.x |
| IBM XL C/C++ | Oui | Depuis version 13 |
| TinyCC | Oui | Support basique |
| PCC | Non | Header guards requis |
| SDCC | Partiel | Selon la cible |
Comparaison Header Guards vs #pragma once
Tableau Comparatif Detaille
| Critere | Header Guards | #pragma once |
|---|---|---|
| Standardisation | Standard C | Extension non standard |
| Portabilite | 100% portable | ~99% (tous compilateurs modernes) |
| Lisibilite | Plus verbeux | Minimaliste |
| Maintenance | Necessite attention | Zero maintenance |
| Performance | Bonne | Potentiellement meilleure |
| Liens symboliques | Fonctionne | Peut echouer |
| Collision de noms | Possible si mal nomme | Impossible |
| Systemes embarques | Toujours supporte | Variable |
| Refactoring | Necessite MAJ des noms | Rien a changer |
Recommandations par Contexte
Utilisez les header guards traditionnels si :
- Vous developpez une bibliotheque destinee a etre largement distribuee
- Votre code doit compiler sur des compilateurs anciens ou exotiques
- Vous travaillez dans l’embarque avec des contraintes de portabilite
- Les conventions de votre organisation l’exigent
- Vous utilisez des systemes de build avec des liens symboliques complexes
// Recommande pour les bibliotheques publiques
#ifndef MYLIB_PUBLIC_API_H
#define MYLIB_PUBLIC_API_H
// API publique de la bibliotheque
#endif /* MYLIB_PUBLIC_API_H */
Utilisez #pragma once si :
- Vous developpez un projet interne avec des compilateurs modernes connus
- Vous privilegiez la simplicite et la maintenabilite
- Votre equipe adopte cette convention
- Vous utilisez des IDE qui generent automatiquement cette directive
// Recommande pour les projets internes modernes
#pragma once
// Code du header
Approche hybride (ceinture et bretelles) :
Certains projets combinent les deux approches pour maximiser la compatibilite tout en beneficiant des optimisations de #pragma once sur les compilateurs qui le supportent.
// Approche hybride - maximum de compatibilite
#ifndef MYPROJECT_MODULE_H
#define MYPROJECT_MODULE_H
#ifdef _MSC_VER
#pragma once
#endif
// Contenu du header
#endif /* MYPROJECT_MODULE_H */
Ou plus simplement :
#pragma once
#ifndef MYPROJECT_MODULE_H
#define MYPROJECT_MODULE_H
// Contenu du header
#endif /* MYPROJECT_MODULE_H */
Organisation des Fichiers d’En-tete
Structure Recommandee d’un Header
Un fichier d’en-tete bien organise suit une structure logique et coherente. Voici un template recommande :
/**
* @file module_name.h
* @brief Description courte du module
* @author Votre Nom
* @date 2025-01-15
*
* Description detaillee du module et de son utilisation.
*/
#ifndef PROJECT_MODULE_NAME_H
#define PROJECT_MODULE_NAME_H
/* ============================================================
* INCLUDES
* ============================================================ */
/* Includes systeme */
#include <stddef.h>
#include <stdint.h>
/* Includes du projet */
#include "project/types.h"
#include "project/config.h"
/* ============================================================
* MACROS ET CONSTANTES
* ============================================================ */
#define MODULE_VERSION_MAJOR 1
#define MODULE_VERSION_MINOR 0
#define MODULE_BUFFER_SIZE 1024
/* ============================================================
* TYPES
* ============================================================ */
/**
* @brief Structure representant un element
*/
typedef struct {
int id;
char name[64];
void *data;
} Element;
/**
* @brief Enumeration des codes de retour
*/
typedef enum {
MODULE_OK = 0,
MODULE_ERROR_INVALID_ARG,
MODULE_ERROR_MEMORY,
MODULE_ERROR_IO
} ModuleResult;
/* ============================================================
* DECLARATIONS DE FONCTIONS
* ============================================================ */
/**
* @brief Initialise le module
* @return MODULE_OK en cas de succes
*/
ModuleResult module_init(void);
/**
* @brief Termine le module et libere les ressources
*/
void module_cleanup(void);
/**
* @brief Cree un nouvel element
* @param name Nom de l'element (copie)
* @return Pointeur vers l'element ou NULL en cas d'erreur
*/
Element *element_create(const char *name);
/**
* @brief Detruit un element
* @param elem Element a detruire (peut etre NULL)
*/
void element_destroy(Element *elem);
#endif /* PROJECT_MODULE_NAME_H */
Forward Declarations
Les forward declarations permettent de declarer l’existence d’un type sans inclure son fichier d’en-tete complet. Cette technique reduit les dependances et accelere la compilation.
// database.h
#ifndef PROJECT_DATABASE_H
#define PROJECT_DATABASE_H
/* Forward declarations au lieu de #include "user.h" et #include "order.h" */
struct User; /* Defini dans user.h */
struct Order; /* Defini dans order.h */
typedef struct Database Database;
Database *db_connect(const char *connection_string);
void db_disconnect(Database *db);
/* Ces fonctions utilisent des pointeurs, pas besoin de la definition complete */
int db_save_user(Database *db, struct User *user);
int db_save_order(Database *db, struct Order *order);
struct User *db_find_user(Database *db, int user_id);
#endif /* PROJECT_DATABASE_H */
Quand utiliser les forward declarations :
- Quand vous n’utilisez que des pointeurs vers le type
- Pour casser les dependances circulaires
- Pour accelerer la compilation de grands projets
Quand vous devez inclure le header complet :
- Quand vous avez besoin de la taille du type (sizeof)
- Quand vous accedez aux membres de la structure
- Quand vous heritez du type (en C++, mais aussi pour les structures imbriquees en C)
Include What You Use (IWYU)
Le principe “Include What You Use” stipule que chaque fichier source doit inclure explicitement tous les headers dont il a directement besoin, et uniquement ceux-la.
Regles IWYU :
- Incluez ce que vous utilisez directement
// user_service.c
// INCORRECT - depend d'une inclusion transitive
#include "database.h" // database.h inclut user.h
void process_user(void) {
struct User *u = user_create("John"); // User vient de user.h
}
// CORRECT - inclusion explicite
#include "database.h"
#include "user.h" // Explicitement inclus car utilise directement
void process_user(void) {
struct User *u = user_create("John");
}
- N’incluez pas ce que vous n’utilisez pas
// INCORRECT - includes inutiles
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h> // Non utilise !
#include <time.h> // Non utilise !
int calculate(int a, int b) {
return a + b; // N'utilise aucun de ces includes !
}
// CORRECT - minimal
int calculate(int a, int b) {
return a + b;
}
- Utilisez l’outil IWYU de Google
# Installation sur Ubuntu/Debian
sudo apt install iwyu
# Utilisation basique
iwyu mon_fichier.c
# Integration avec CMake
cmake -DCMAKE_CXX_INCLUDE_WHAT_YOU_USE=iwyu ..
Hierarchie des Includes Recommandee
Organisez vos includes dans un ordre logique et coherent :
// 1. Header correspondant au fichier source (pour les .c)
#include "my_module.h"
// 2. Headers du meme projet (ordre alphabetique)
#include "project/config.h"
#include "project/types.h"
#include "project/utils.h"
// 3. Headers de bibliotheques tierces (ordre alphabetique)
#include <openssl/ssl.h>
#include <zlib.h>
// 4. Headers systeme C standard (ordre alphabetique)
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 5. Headers systeme specifiques a l'OS (ordre alphabetique)
#ifdef _WIN32
#include <windows.h>
#else
#include <pthread.h>
#include <unistd.h>
#endif
Bonnes Pratiques
Regles Essentielles
1. Un header = une responsabilite
Chaque fichier d’en-tete devrait avoir une responsabilite unique et bien definie. Evitez les “headers fourre-tout”.
// INCORRECT - header trop general
// utils.h contient string_utils, math_utils, file_utils, network_utils...
// CORRECT - headers specialises
// string_utils.h - fonctions de manipulation de chaines
// math_utils.h - fonctions mathematiques
// file_utils.h - fonctions de gestion de fichiers
2. Minimisez les includes dans les headers
Preferez les forward declarations quand c’est possible. Mettez les includes supplementaires dans les fichiers .c.
// header.h - minimal
#ifndef MODULE_H
#define MODULE_H
struct OtherType; // Forward declaration
void process(struct OtherType *obj);
#endif
// source.c - includes complets
#include "header.h"
#include "other_type.h" // Include complet ici
#include <stdio.h> // Et les autres includes necessaires
3. Ne definissez jamais de variables dans un header
// INCORRECT - definition dans le header
#ifndef CONFIG_H
#define CONFIG_H
int global_counter = 0; // ERREUR : sera defini dans chaque .c qui inclut ce header !
#endif
// CORRECT - declaration extern dans le header
#ifndef CONFIG_H
#define CONFIG_H
extern int global_counter; // Declaration seulement
#endif
// config.c - definition unique
#include "config.h"
int global_counter = 0; // Definition dans un seul fichier .c
4. Utilisez des commentaires de fin de bloc significatifs
#ifndef VERY_LONG_MODULE_NAME_H
#define VERY_LONG_MODULE_NAME_H
// ... 500 lignes de code ...
#endif /* VERY_LONG_MODULE_NAME_H */ // Aide a retrouver le debut
5. Protegez les declarations pour C++
Si votre code C peut etre utilise depuis C++, ajoutez la protection extern "C" :
#ifndef MY_C_LIBRARY_H
#define MY_C_LIBRARY_H
#ifdef __cplusplus
extern "C" {
#endif
void my_c_function(int x);
int another_c_function(const char *str);
#ifdef __cplusplus
}
#endif
#endif /* MY_C_LIBRARY_H */
6. Evitez les macros qui changent le comportement
// INCORRECT - comportement variable selon l'ordre d'inclusion
#ifdef USE_FAST_MATH
#define sin(x) fast_sin(x)
#endif
// CORRECT - interface explicite
double standard_sin(double x);
double fast_sin(double x); // L'appelant choisit explicitement
Pieges Courants
Erreurs Frequentes a Eviter
1. Oublier le #define apres #ifndef
// INCORRECT - le #define est oublie !
#ifndef MY_HEADER_H
// #define MY_HEADER_H // OUBLIE !
// contenu...
#endif
// Ce header sera inclus a chaque fois !
2. Utiliser le meme nom de macro pour plusieurs headers
// file1.h
#ifndef UTILS_H // Nom trop generique !
#define UTILS_H
// ...
#endif
// file2.h (dans un autre repertoire)
#ifndef UTILS_H // Meme nom ! Un seul header sera inclus !
#define UTILS_H
// ...
#endif
3. Placer du code avant le header guard
// INCORRECT - include avant le guard
#include <stdio.h> // Ce sera inclus a chaque fois !
#ifndef MY_HEADER_H
#define MY_HEADER_H
// ...
#endif
4. Inclusions circulaires non gerees
// a.h
#ifndef A_H
#define A_H
#include "b.h" // b.h inclut a.h !
struct A { struct B *b; };
#endif
// b.h
#ifndef B_H
#define B_H
#include "a.h" // a.h inclut b.h !
struct B { struct A *a; };
#endif
// SOLUTION - utiliser des forward declarations
// a.h
#ifndef A_H
#define A_H
struct B; // Forward declaration
struct A { struct B *b; };
#endif
// b.h
#ifndef B_H
#define B_H
struct A; // Forward declaration
struct B { struct A *a; };
#endif
5. Confondre #ifndef et #ifdef
// INCORRECT - logique inversee !
#ifdef MY_HEADER_H // Si defini, ne PAS inclure (inverse de ce qu'on veut)
#define MY_HEADER_H
// ...
#endif
// CORRECT
#ifndef MY_HEADER_H // Si NON defini, inclure
#define MY_HEADER_H
// ...
#endif
6. Utiliser des noms reserves
// INCORRECT - noms reserves par le standard
#ifndef _HEADER_H // Commence par underscore + majuscule
#ifndef __header__ // Contient double underscore
#ifndef __HEADER_H__ // Les deux problemes
// CORRECT
#ifndef PROJECT_HEADER_H
7. Header guards dans les fichiers .c
// my_module.c - PAS besoin de header guards ici !
// Les .c ne sont jamais inclus avec #include
#include "my_module.h"
void my_function(void) {
// implementation
}
Conclusion
La gestion correcte des inclusions multiples est un pilier fondamental de la programmation C professionnelle. Les header guards traditionnels offrent une solution portable et standardisee, tandis que #pragma once propose une alternative plus simple pour les projets modernes.
Pour resumer les points cles de cet article :
-
Choisissez une approche et restez coherent dans tout votre projet. Melanger les approches sans logique cree de la confusion.
-
Adoptez une convention de nommage stricte pour vos header guards :
PROJET_CHEMIN_FICHIER_Hest une excellente base. -
Organisez vos headers de maniere logique : un header = une responsabilite, includes minimaux, forward declarations quand possible.
-
Appliquez le principe IWYU : incluez explicitement ce que vous utilisez, rien de plus.
-
Evitez les pieges classiques : noms reserves, inclusions circulaires, code avant les guards.
En suivant ces bonnes pratiques, vous construirez des projets C plus robustes, plus maintenables et plus rapides a compiler. La rigueur dans la gestion des fichiers d’en-tete distingue souvent le code amateur du code professionnel.
References et Ressources
- Include What You Use (IWYU) - Outil Google pour analyser les includes
- GCC Preprocessor Documentation - Documentation officielle du preprocesseur GCC
- C Programming FAQ - Headers - FAQ sur le preprocesseur C
- ISO C Standard - Norme C17 officielle
- Effective C par Robert C. Seacord - Livre de reference sur le C moderne
In-Article Ad
Dev Mode
Tags
Mahmoud DEVO
Senior Full-Stack Developer
I'm a passionate full-stack developer with 10+ years of experience building scalable web applications. I write about Vue.js, Node.js, PostgreSQL, and modern DevOps practices.
Enjoyed this article?
Subscribe to get more tech content delivered to your inbox.
Related Articles
Bit-fields et tableaux en C : guide pratique pour optimiser la memoire
Maitrisez les bit-fields et tableaux en C. Apprenez a creer des structures compactes, acceder aux elements et iterer efficacement sur vos donnees.
Programmation C : Bits, pointeurs et bonnes pratiques
Maîtrisez les pièges courants en C : évaluation des champs de bits, arithmétique des pointeurs, commentaires multi-lignes et comparaison de flottants.
Enums et Switch en C : Guide Complet des Bonnes Pratiques
Maitrisez les enumerations et instructions switch en C : declaration, valeurs explicites, flags bitwise et gestion exhaustive des cas.