Menu
CoddyTech

Wrapper genérico

Parte de la sección Programación Orientada a Objetos del Journey de C de Coddy. Lección 50 de 61.

Un void* por sí solo puede almacenar cualquier dato, pero tiene un defecto crítico: pierdes la pista de qué tipo contiene. Para crear contenedores genéricos realmente útiles, debemos combinar el puntero a los datos con información de tipo. Aquí es donde entra en juego el patrón Generic Wrapper.

La idea es simple: crea una estructura que agrupe un void* con un enumerado que identifique el tipo almacenado. De este modo, el envoltorio siempre sabe cómo interpretar su contenido.

typedef enum {
    TYPE_INT,
    TYPE_STRING
} DataType;
typedef struct {
    void* data;
    DataType type;
} Wrapper;

Al almacenar datos, asignas memoria para el valor real y registras su tipo. Al recuperarlos, compruebas el tipo antes de convertirlo:

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);
    }
}

Este patrón es la base para crear contenedores genéricos con seguridad de tipos en C. El enum actúa como una etiqueta de tipo en tiempo de ejecución, lo que permite que tu código tome decisiones seguras sobre cómo manejar los datos almacenados.

challenge icon

Desafío

Fácil

Construyamos un sistema genérico de envoltorios con seguridad de tipos que pueda almacenar un entero o una cadena, realizando un seguimiento del tipo que contiene para que podamos recuperar e imprimir los datos de forma segura más adelante.

Organizarás tu código en tres archivos:

  • wrapper.h: Define un enum DataType con los valores TYPE_INT y TYPE_STRING. Después, define una estructura Wrapper que agrupe un puntero de datos void* con un campo DataType. Declara los prototipos de las funciones para crear envoltorios e imprimir su contenido.
  • wrapper.c: Implementa la funcionalidad del envoltorio:
    • wrap_int: recibe un entero, reserva memoria para él, almacena el valor y devuelve un Wrapper con la etiqueta de tipo correspondiente
    • wrap_string: recibe una cadena (char*), reserva memoria y copia la cadena, y devuelve un Wrapper con la etiqueta de tipo de cadena
    • print_wrapper: comprueba la etiqueta de tipo e imprime los datos adecuadamente (el entero tal cual, la cadena tal cual)
    • free_wrapper: libera los datos reservados dinámicamente dentro del envoltorio
  • main.c: Une todo. Lee un indicador de tipo (i para un entero, s para una cadena), seguido del valor. Crea el envoltorio correspondiente, imprime su contenido y libera la memoria.

Tu programa recibirá dos entradas:

  1. Un indicador de tipo: i para un entero o s para una cadena
  2. El valor que se envolverá

Salida de ejemplo cuando las entradas son i y 42:

42

Salida de ejemplo cuando las entradas son s y Hello:

Hello

Salida de ejemplo cuando las entradas son i y -100:

-100

Salida de ejemplo cuando las entradas son s y Generic Programming:

Generic Programming

Recuerda usar protectores de inclusión en tu archivo de encabezado. Para copiar cadenas, reserva suficiente espacio para la cadena más el terminador nulo usando strlen y strcpy.

Pruébalo tú mismo

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

int main() {
    char type;
    scanf("%c", &type);
    getchar(); // consumir el salto de línea
    
    Wrapper w;
    
    if (type == 'i') {
        int value;
        scanf("%d", &value);
        // TODO: Crear un wrapper de entero usando wrap_int
        
    } else if (type == 's') {
        char str[256];
        fgets(str, sizeof(str), stdin);
        // Eliminar el salto de línea final si está presente
        str[strcspn(str, "\n")] = '\0';
        // TODO: Crear un wrapper de cadena usando wrap_string
        
    }
    
    // TODO: Imprimir el contenido del wrapper usando print_wrapper
    
    // TODO: Liberar la memoria del wrapper usando free_wrapper
    
    return 0;
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos

Practica por tu cuenta: Compilador de C online