Cómo utilizar un puntero de función en una estructura C?

Quiero aprender más sobre el uso de punteros a función en las estructuras de C como una forma de emular a objetos programación orientada a objetos, pero en mi búsqueda, me he encontrado con preguntas como este donde la respuesta es simplemente el uso de un puntero a función, sin describir la forma en que funcione.

Mi mejor conjetura es algo como esto

#include <stdio.h>
#include <stdlib.h>

struct my_struct
{
    int data;
    struct my_struct* (*set_data) (int);
};

struct my_struct* my_struct_set_data(struct my_struct* m, int new_data)
{
    m->data = new_data;
    return m;
}

struct my_struct* my_struct_create() {
    struct my_struct* result = malloc((sizeof(struct my_struct)));
    result->data = 0;
    result->set_data = my_struct_set_data;
    return result;
}

int main(int argc, const char* argv[])
{
    struct my_struct* thing = my_struct_create();
    thing->set_data(1);
    printf("%d\n", thing->data);
    free(thing);
    return 0;
}

Pero que me dan las advertencias del compilador warning: assignment from incompatible pointer type, por lo que obviamente estoy haciendo algo mal. Podría alguien por favor proporcione un pequeño pero completo ejemplo de cómo utilizar un puntero de función en una estructura C correctamente?

Mi clase se enseña en C no hace mención alguna de estas. Me pregunto si estos son en realidad utilizados por los programadores de C. ¿Cuáles son las ventajas y desventajas del uso de punteros a función en las estructuras de C?

La advertencia del compilador puede ser debido a que la lista de argumentos de la función real no coincide con la lista de argumentos en la estructura var: la función real que ha (struct my_struct *, int) y la definición de la estructura sólo tiene (int)
Cuál debería cambiar?
Usted debe cambiar el puntero de función en la estructura de la definición de struct my_struct* (*set_data) (struct my_struct*, int); si desea asignar my_struct_set_data().

OriginalEl autor Eva | 2012-07-14

2 respuestas

  1. 10

    En su estructura definición, el cambio a

    struct my_struct
    {
        int data;
        struct my_struct* (*set_data) (struct my_struct*,int);
    };

    y ahora que utilizar el puntero a función principal como

    thing->set_data(thing,1);
    Esto compila bien. ¿Cuáles son las ventajas de este método sobre el uso de la my_struct_set_data función? Desventajas?
    Podría usted comentar sobre tu pregunta un poco más? Si lo que quieres decir, ¿cuáles son las ventajas de tener un struct en C que contiene punteros a función que (presumiblemente) operan en la estructura en sí, el más útil ventaja que podía pensar es el polimorfismo. Por ejemplo, definir varios set_data() funciones, y cualquier estructura que podría elegir un determinado set_data() función que se adapte a ti. Entonces, cuando usted está en el procesamiento de varios de sus estructuras, no es necesario elegir qué conjunto de datos en función de la particular estructura que se va a utilizar; ya está “integrado” en la estructura.
    Usted simplemente no puede esperar thing->set_data(value) se comportan de la misma manera que lo haría en C++. La función no no tiene alguna referencia a thing. Usted puede pensar acerca de una llamada de método en C++ se convierte de thing->do_stuff() a ThingsClass_do_stuff(thing) o incluso thing->_vtable->do_stuff(thing) si el método era virtual.
    Supongo que mi pregunta real con las ventajas y desventajas que es cuando el uso de uno sobre el otro? Es costumbre tener un my_struct_set_data método y un set_data método dentro de mi estructura o hacer los programadores de C normalmente sólo uso el primero y principalmente el uso de la segunda para el polimorfismo?
    Personalmente, la idea de usar ambos métodos juntos me asusta. Acabo de escribir un my_struct_set_data() método y salir de la estructura sin ningún tipo de punteros a función, pero eso es sólo conmigo. Así que si yo soy la representante de la típica programador de C, entonces sí, los programadores de C normalmente sólo uso el primero y principalmente utilizar la segunda para el propósito expreso de polimorfismo!

    OriginalEl autor

  2. 12

    La respuesta dada por Andy guardar Lejos de las correcciones de mi advertencia del compilador, pero no responde a mi segunda pregunta. Los comentarios a la respuesta dada por eddieantonio y Niklas R respuesta a mi segunda pregunta, pero no resuelve mi advertencia del compilador. Así que yo soy la agrupación de ellos juntos en una respuesta.

    C no es orientado a objetos y tratando de emular el diseño orientado a objetos en C por lo general resulta en un mal estilo. La duplicación de los métodos llamados en sus estructuras de modo que puedan ser llamado usando un puntero a la estructura como la que tengo en mi ejemplo no es la excepción. (Y, francamente, viola SECO.) Los punteros a función en las estructuras son más útiles para el polimorfismo. Por ejemplo, si yo tuviera un struct vector que representa un contenedor genérico para una secuencia lineal de elementos, puede ser útil para almacenar un comparison_func miembro que era un puntero a función para permitir la búsqueda y la ordenación a través del vector. Cada instancia del vector podría utilizar una diferente función de comparación. Sin embargo, en el caso de una función que opera sobre la estructura en sí, es el mejor estilo para tener una sola función por separado que no está duplicada en la estructura.

    Esto hace que la respuesta de lo que es correcto más complicado. Es lo que es correcto cómo hacer que mi ejemplo anterior compilar? Es cómo volver a formatear mi ejemplo anterior para que tenga un buen estilo? O es lo que es un ejemplo de una estructura que utiliza un puntero a la función de la forma programador de C lo va a hacer? En la formulación de mi pregunta, no pude prever que la respuesta no sea que mi pregunta estaba mal. La integridad, la voy a poner un ejemplo de cada respuesta a la pregunta.

    La fijación de la Advertencia del Compilador

    #include <stdio.h>
    #include <stdlib.h>
    
    struct my_struct
    {
        int data;
        struct my_struct* (*set_data) (struct my_struct*, int);
    };
    
    struct my_struct* my_struct_set_data(struct my_struct* m, int new_data)
    {
        m->data = new_data;
        return m;
    }
    
    struct my_struct* my_struct_create()
    {
        struct my_struct* result = malloc((sizeof(struct my_struct)));
        result->data = 0;
        result->set_data = my_struct_set_data;
        return result;
    }
    
    int main(int argc, const char* argv[])
    {
        struct my_struct* thing = my_struct_create();
        thing->set_data(thing, 1);
        printf("%d\n", thing->data);
        free(thing);
        return 0;
    }

    Volver a formatear el Estilo

    #include <stdio.h>
    #include <stdlib.h>
    
    struct my_struct
    {
        int data;
    };
    
    void my_struct_set_data(struct my_struct* m, int new_data)
    {
        m->data = new_data;
    }
    
    struct my_struct* my_struct_create()
    {
        struct my_struct* result = malloc((sizeof(struct my_struct)));
        result->data = 0;
        return result;
    }
    
    int main(int argc, const char* argv[])
    {
        struct my_struct* thing = my_struct_create();
        my_struct_set_data(thing, 1);
        printf("%d\n", thing->data);
        free(thing);
        return 0;
    }

    Lo que demuestra un Uso de la Función de Puntero en las Estructuras

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    struct my_struct
    {
        void* data;
        int (*compare_func)(const void*, const void*);
    };
    
    int my_struct_compare_to_data(struct my_struct* m, const void* comparable)
    {
        return m->compare_func(m->data, comparable);
    }
    
    struct my_struct* my_struct_create(void* initial_data,
            int (*compare_func)(const void*, const void*))
    {
        struct my_struct* result = malloc((sizeof(struct my_struct)));
        result->data = initial_data;
        result->compare_func = compare_func;
        return result;
    }
    
    int int_compare(const void* a_pointer, const void* b_pointer)
    {
        return *(int*)a_pointer - *(int*) b_pointer;
    }
    
    int string_compare(const void* a_pointer, const void* b_pointer)
    {
        return strcmp(*(char**)a_pointer, *(char**)b_pointer);
    }
    
    int main(int argc, const char* argv[])
    {
        int int_data = 42;
        struct my_struct* int_comparator =
                my_struct_create(&int_data, int_compare);
    
        char* string_data = "Hello world";
        struct my_struct* string_comparator =
                 my_struct_create(&string_data, string_compare);
    
        int int_comparable = 42;
        if (my_struct_compare_to_data(int_comparator, &int_comparable) == 0)
        {
            printf("The two ints are equal.\n");
        }
    
        char* string_comparable = "Goodbye world";
        if (my_struct_compare_to_data(string_comparator,
                &string_comparable) > 0)
        {
            printf("The first string comes after the second.\n");
        }
    
        free(int_comparator);
        free(string_comparator);
    
        return 0;
    }
    +1 para la síntesis. Ver también esta relacionado con respuesta.

    OriginalEl autor

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *