Menu
Coddy logo textTech

Wrapper générique

Fait partie de la section Programmation Orientée Objet du Journey C de Coddy. Leçon 50 sur 61.

Un void* seul peut stocker n’importe quelle donnée, mais il présente un défaut critique : vous perdez la trace du type qu’il contient. Pour construire des conteneurs génériques réellement utiles, nous devons associer le pointeur de données aux informations de type. C’est là qu’intervient le modèle du wrapper générique.

L’idée est simple : créer une structure qui regroupe un void* avec une énumération qui identifie le type stocké. Ainsi, le wrapper sait toujours comment interpréter son contenu.

typedef enum {
    TYPE_INT,
    TYPE_STRING
} DataType;

typedef struct {
    void* data;
    DataType type;
} Wrapper;

Lors du stockage de données, vous allouez de la mémoire pour la valeur réelle et enregistrez son type. Lors de la récupération, vous vérifiez le type avant d’effectuer la conversion :

Wrapper wrap_int(int value) {
    int* p = malloc(sizeof(int));
    *p = value;
    return (Wrapper){ .data = p, .type = TYPE_INT };
}

void print_wrapper(Wrapper* w) {
    if (w->type == TYPE_INT) {
        printf("%d\n", *(int*)w->data);
    } else if (w->type == TYPE_STRING) {
        printf("%s\n", (char*)w->data);
    }
}

Ce modèle constitue la base pour créer des conteneurs génériques à typage sûr en C. L’énumération agit comme une balise de type à l’exécution, permettant à votre code de prendre des décisions sûres sur la manière de traiter les données stockées.

challenge icon

Défi

Facile

Construisons un système générique de wrappers sûr du point de vue des types, capable de stocker soit un entier, soit une chaîne de caractères, tout en gardant trace du type qu’il contient afin de pouvoir récupérer et afficher les données en toute sécurité par la suite.

Vous organiserez votre code dans trois fichiers :

  • wrapper.h : définissez une énumération DataType avec les valeurs TYPE_INT et TYPE_STRING. Définissez ensuite une structure Wrapper qui regroupe un pointeur de données void* et un champ DataType. Déclarez les prototypes des fonctions permettant de créer les wrappers et d’afficher leur contenu.
  • wrapper.c : implémentez les fonctionnalités du wrapper :
    • wrap_int : prend un entier, lui alloue de la mémoire, stocke la valeur et renvoie un Wrapper avec l’étiquette de type appropriée
    • wrap_string : prend une chaîne de caractères (char*), alloue de la mémoire, copie la chaîne et renvoie un Wrapper avec l’étiquette de type chaîne
    • print_wrapper : vérifie l’étiquette de type et affiche les données de manière appropriée (l’entier tel quel, la chaîne telle quelle)
    • free_wrapper : libère les données allouées dynamiquement à l’intérieur du wrapper
  • main.c : assemblez le tout. Lisez un indicateur de type (i pour un entier, s pour une chaîne), suivi de la valeur. Créez le wrapper approprié, affichez son contenu et libérez la mémoire.

Votre programme recevra deux entrées :

  1. Un indicateur de type : i pour un entier ou s pour une chaîne
  2. La valeur à encapsuler

Exemple de sortie lorsque les entrées sont i et 42 :

42

Exemple de sortie lorsque les entrées sont s et Hello :

Hello

Exemple de sortie lorsque les entrées sont i et -100 :

-100

Exemple de sortie lorsque les entrées sont s et Generic Programming :

Generic Programming

N’oubliez pas d’utiliser des gardes d’inclusion dans votre fichier d’en-tête. Pour copier une chaîne, allouez suffisamment d’espace pour la chaîne et le terminateur nul à l’aide de strlen et strcpy.

Essayez vous-même

#include <stdio.h>
#include <string.h>
#include "wrapper.h"

int main() {
    char type;
    scanf("%c", &type);
    getchar(); // consommer le saut de ligne
    
    Wrapper w;
    
    if (type == 'i') {
        int value;
        scanf("%d", &value);
        // TODO: Créer un wrapper d'entier en utilisant wrap_int
        
    } else if (type == 's') {
        char str[256];
        fgets(str, sizeof(str), stdin);
        // Supprimer le saut de ligne final s'il est présent
        str[strcspn(str, "\n")] = '\0';
        // TODO: Créer un wrapper de chaîne en utilisant wrap_string
        
    }
    
    // TODO: Afficher le contenu du wrapper en utilisant print_wrapper
    
    // TODO: Libérer la mémoire du wrapper en utilisant free_wrapper
    
    return 0;
}
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation Orientée Objet

Entraînez-vous par vous-même : Compilateur C en ligne