2012-10-19 7 views
7

Non sono nuovo alla programmazione in C. Ma non capisco quale sia l'utilità per mantenere il puntatore a funzionare come membro di una struttura in C., ad es.Come i puntatori a funzionare come membro della struct sono utili in C?

// Fist Way: To keep pointer to function in struct 
    struct newtype{ 
     int a; 
     char c; 
     int (*f)(struct newtype*); 
    } var; 
    int fun(struct newtype* v){ 
     return v->a; 
    } 

    // Second way: Simple 
    struct newtype2{ 
     int a; 
     char c; 
    } var2; 
    int fun2(struct newtype2* v){ 
     return v->a; 
    } 

    int main(){ 

     // Fist: Require two steps 
     var.f=fun; 
     var.f(&var); 

     //Second : simple to call 
     fun2(&var2);  
    } 

Does programmatori usano per dare forma Object Oriented (OO) a lì codice C e fornire oggetto astratto? O per rendere il codice tecnico.

Penso che nel codice precedente il secondo modo sia più delicato e anche piuttosto semplice. In primo piano, dobbiamo ancora passare &var, anche fun() è membro di struct.

Se è utile mantenere il puntatore della funzione all'interno della definizione della struttura, si prega di spiegare il motivo.

+2

Pensare alle funzioni virtuali nelle classi C++. Sono implementati in modo simile sotto il cofano. –

+2

[Per quanto riguarda i puntatori di funzione nei sistemi incorporati] (http://stackoverflow.com/questions/4836245/function-pointers-in-embedded-systems- are-they-useful). – Lundin

+0

Grazie a @Lundin! risposta davvero molto utile e interessante che ho trovato lì. –

risposta

11

Fornire un puntatore alla funzione su una struttura può consentire di scegliere dinamicamente quale funzione eseguire su una struttura.

struct newtype{ 
    int a; 
    int b; 
    char c; 
    int (*f)(struct newtype*); 
} var; 


int fun1(struct newtype* v){ 
     return v->a; 
    } 

int fun2(struct newtype* v){ 
     return v->b; 
    } 

void usevar(struct newtype* v) { 
    // at this step, you have no idea of which function will be called 
    var.f(&var); 
} 

int main(){ 
     if (/* some test to define what function you want)*/) 
      var.f=fun; 
     else 
      var.f=fun2; 
     usevar(var); 
    } 

Questo ti dà la possibilità di mantenere solo un codice, ma chiamando due diverse funzioni piuttosto che il tuo test è valido o meno.

+0

Questo è tutto pensare na ... Chiamato polimorfismo in C++ (tempo di esecuzione o associazione compilazione) –

1

Questo può essere particolarmente utile nel sistema incorporato o nella scrittura del driver. Le funzioni sono chiamate usando i puntatori di funzione.

ad es.

struct_my_filesystem.open=my_open; 
struct_my_filesystem.read=my_read; 

ecc

10

Il suo utile se si sta cercando di fare una sorta di "basata oggetto" di programmazione.

Se hai mai visto il codice sorgente del motore di Quake 3, puoi vedere chiaramente che la maggior parte delle "entità" hanno attributi che li definiscono e il lavoro che fanno [che sono i puntatori di funzione].

Segregazione di attributi e funzioni (tramite i puntatori di funzione in C) definisce gli attributi e le azioni dell'oggetto "struct" che possono eseguire.

Ad esempio:

struct _man{ 
    char name[]; 
    int age; 
    void (*speak)(char *text); 
    void (*eat)(Food *foodptr); 
    void (*sleep)(int hours); 
    /*etc*/ 
}; 

void grijesh_speak(char *text) 
{ 
    //speak; 
} 

void grijesh_eat(Food *food) 
{ 
    //eat 
} 

void grijesh_sleep(int hours) 
{ 
    //sleep 
} 

void init_struct(struct _man *man) 
{ 
    if(man == NULL){ man = malloc(sizeof(struct _man));} 
     strcpy(*man.name,"Grijesh"); 
     man->age = 25; 
     man->speak = grijesh_speak; 
     man->eat = grijesh_food; 
     man->sleep = grijesh_sleep; 
//etc 
} 

//so now in main.. i can tell you to either speak, or eat or sleep. 

int main(int argc, char *argv[]) 
{ 
    struct _man grijesh; 
    init_struct(&grijesh); 
    grijesh.speak("Babble Dabble"); 
    grijesh.sleep(10); 
    return 0; 
} 
1

volte in C è necessario chiamare una funzione, senza conoscere in anticipo la sua attuazione. Per esempio. se stai sviluppando una libreria autonoma utilizzata in diversi progetti. In tal caso, ha perfettamente senso aggiungere un puntatore a una struttura di contesto e passarlo insieme alle funzioni della libreria. Le funzioni della libreria possono quindi chiamare la funzione in fase di esecuzione senza dover includere i file di intestazione che lo definiscono.

È in effetti simile a ciò che si fa quando si esegue la programmazione orientata agli oggetti. In C, di solito passa attorno alle variabili di contesto, ad es. una struttura, che raggruppa un insieme di variabili e possibilmente funzioni che sono significative per quel contesto. Questo è vicino all'eqvuivalent nella programmazione OO, in cui istanziate una classe e impostate le variabili richieste sull'istanza.

2

L'ho usato in passato per implementare contenitori generici in C.

Ad esempio:

typedef struct generic_list_node { 
    void *data; 
    struct generic_list_node *next; 
} generic_list_node_t; 

typedef struct generic_list { 
    generic_list_node_t *head; 
    void *(*copy)(void *data);     
    void (*delete)(void *data);     
    int (*compare)(void *lhs, void *rhs);  
    void (*display)(void *data, FILE *stream); 
} generic_list_t; 

La struttura della lista stessa è data-agnostic, utilizzando void * per rappresentare elementi di dati, e delegati tutte le operazioni di tipo-consapevole verso le funzioni indicate dalle frecce sopra:

int insert(generic_list_t l, void *data) 
{ 
    generic_list_node_t *cur = l.head; 
    generic_list_node_t *new = malloc(sizeof *new); 
    if (new) 
    { 
    new->data = l.copy(data); 
    new->next = NULL; 

    if (l.head == NULL) 
    { 
     l.head = new; 
    } 
    else 
    { 
     while (cur->next && l.compare(new->data, cur->data) > 0) 
     cur = cur->next; 
     new->next = cur->next; 
     cur->next = new; 
     printf("Successfully added "); 
     l.display(data, stdout); 
     printf(" to list\n"); 

    } 
    return 1; 
    } 

    return 0; 
} 

1. Per la definizione opportunamente sciolti "generica" ​​e "contenitore"

+0

Uso eccellente ... Grazie –

1

Ecco un progetto per aiutare a spiegare l'utilità dei puntatori di funzione. Prova a creare una libreria basata su c che fornisca ereditarietà e polimorfismo. Oppure, prova a ricreare "C with Classes". I puntatori di funzioni all'interno delle strutture saranno vitali. http://www.cs.rit.edu/~ats/books/ooc.pdf

+0

Questo era un riferimento eccellente ... Grazie! –

Problemi correlati