Pseudo-genéricos en C

4 minutos de lectura

avatar de usuario
fb55

Necesito implementar algunos métodos que hagan cosas con diferentes tipos de matrices de números. Por lo general, usaría genéricos para ese trabajo, pero como C no los proporciona, ahora estoy tratando de emularlos usando macros.

Aquí hay un ejemplo de lo que estoy tratando de hacer:

#ifndef TYPE
#define TYPE int
#endif

TYPE get_minimum_##TYPE (TYPE * nums, int len){
    TYPE min = nums[0];

    for (int i = 1; i < len; i++) {
        if (nums[i] < min) {
            min = nums[i];
        }
    }

    return min;
}

Sin embargo, esto no se compilará. El mensaje de error de sonido:

error: esperado ‘;’ después del declarador de nivel superior

¿Hay alguna manera de hacer esto en C? ¿O necesito implementar esto para cada tipo a mano?

  • Para tu información, los genéricos en C # y Java son una instalación de tiempo de ejecución.

    – Daniel A. Blanco

    13 mayo 2013 a las 12:44

  • Si desea leer un poco más sobre “plantillas”/”genéricos” en C, puede leer esta pregunta. Hay algunas respuestas interesantes 🙂

    – Jehan

    13 mayo 2013 a las 13:33

avatar de usuario
pablo r

Puede hacer algo como esto en un archivo de encabezado:

//
// generic.h
//

#define TOKENPASTE(x, y) x ## y

#define GET_MINIMUM(T) TOKENPASTE(get_minimum_, T)

TYPE GET_MINIMUM (TYPE) (TYPE * nums, size_t len){
    TYPE min = nums[0];

    for (size_t i = 1; i < len; i++) {
        if (nums[i] < min) {
            min = nums[i];
        }
    }

    return min;
}

y luego #include en un archivo fuente para cada tipo requerido, por ejemplo:

//
// generic.c
//

#define TYPE int
#include "generic.h"
#undef TYPE

#define TYPE float
#include "generic.h"
#undef TYPE

Puede probar esto ejecutándolo a través del preprocesador:

$ gcc -E generic.c 

int get_minimum_int (int * nums, size_t len){
    int min = nums[0];

    for (size_t i = 1; i < len; i++) {
        if (nums[i] < min) {
            min = nums[i];
        }
    }

    return min;
}

float get_minimum_float (float * nums, size_t len){
    float min = nums[0];

    for (size_t i = 1; i < len; i++) {
        if (nums[i] < min) {
            min = nums[i];
        }
    }

    return min;
}

avatar de usuario
jehan

En realidad, lo mejor que puede hacer es definir una macro que generará la función para el tipo dado.

#define define_get_minimum(T) \
T get_minimum_##T(T* nums, int len){ \
    T min = nums[0]; \
    for (int i = 1; i < len; i++) { \
        if (nums[i] < min) { \
            min = nums[i]; \
        } \
    } \
    return min; \
}

Luego, puede llamar a esa macro para definir las especializaciones que necesita (con la plantilla de C++, el compilador hace algo similar automáticamente).

define_get_minimum(int)
define_get_minimum(double)
define_get_minimum(float)

Otra cosa que un compilador de C++ hace automáticamente es deducir la función sobrecargada que necesita. No puede tener eso en C, por lo que tendrá que decir que está usando la especialización en ti. Puede simular una sintaxis similar a una plantilla para su función con la siguiente macro (el C++ <> simplemente son reemplazados por ()):

#define get_minimum(T) get_minimum_##T

Entonces, deberías poder llamarlo de la siguiente manera:

int main()
{
    // Define arr as char* array...
    // Do stuff...
    int res = get_minimum(int)(arr, 3);
}

No probé este código, pero debería funcionar.

  • Me gusta el estilo de la llamada final, pero estaba tratando de archivar esto sin macros grandes.

    – fb55

    14 de mayo de 2013 a las 9:47

  • @ fb55 Bueno, genérico y no grande no son tan compatibles en C 🙂

    – Jehan

    14 mayo 2013 a las 16:24

  • Eso es lo que me gustó de la respuesta de @PaulR: la macro era bastante corta y se podía reutilizar en otros lugares 🙂

    – fb55

    14 mayo 2013 a las 16:27

  • @ fb55 El problema es que depende de un parámetro de tiempo de compilación. Con su versión, no se puede utilizar el float y el int versión de la función en la misma unidad de compilación :/

    – Jehan

    14 mayo 2013 a las 16:29

  • Actualicé mi respuesta ahora para mostrar cómo generar múltiples funciones para todos los tipos requeridos en una unidad de traducción.

    – Pablo R.

    14 mayo 2013 a las 18:00

También puede usar punteros de función (matriz de punteros de función), que no sean una declaración de cambio, y pasar el argumento del cambio como índice a la matriz.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad