2012-10-19 4 views
7

Ich bin nicht neu in der C-Programmierung. Aber ich verstehe nicht, was sinnvoll ist, um den Zeiger als Strukturelement in C zu halten, z.Wie Zeiger, um als Strukturelement in C nützlich zu sein?

// 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 Programmierer verwenden es objektorientierte (OO) Form gibt C-Code und bieten abstraktes Objekt zu geben? Oder Code technisch aussehen zu lassen.

Ich denke, im obigen Code ist der zweite Weg sanfter und auch ziemlich einfach. In erster Linie müssen wir noch &var10 übergeben, auch fun() ist Mitglied von struct.

Wenn es gut ist, Funktionszeiger in Struct-Definition zu halten, bitte helfen, den Grund zu erklären.

+2

Denken Sie an virtuelle Funktionen in C++ - Klassen. Sie sind in ähnlicher Weise unter der Haube implementiert. –

+2

[In Bezug auf Funktionszeiger in eingebetteten Systemen] (http://stackoverflow.com/questions/4836245/function-pointers-in-embedded-systems-are-theyususeful). – Lundin

+0

Danke @Lundin! wirklich sehr hilfreiche und interessante Antwort, die ich dort gefunden habe. –

Antwort

11

Wenn Sie einen Zeiger für die Funktion einer Struktur angeben, können Sie dynamisch auswählen, welche Funktion für eine Struktur ausgeführt werden soll.

Dies gibt Ihnen die Möglichkeit, nur einen Code zu pflegen, aber zwei verschiedene Funktionen aufrufen, eher Ihren Test gültig ist oder nicht.

+0

Das ist alles denken na ... Genannten Polymorphismus in C++ (Laufzeit oder Compile-Bindung) –

1

Dies kann besonders nützlich sein beim Embedded System oder beim Schreiben von Treibern. Die Funktionen werden mit Funktionszeigern aufgerufen.

z.B.

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

etc

10

Sein nützlich, wenn Sie versuchen, eine Art „Objekt basiert“ Programmierung zu tun.

Wenn Sie jemals den Quellcode der Quake 3-Engine gesehen haben, können Sie klar sehen, dass die meisten "Entitäten" Attribute haben, die sie definieren, und die Arbeit, die sie tun [welche die Funktionszeiger sind].

Das Trennen von Attributen und Funktionen (über Funktionszeiger in C) definiert Attribute und Aktionen eines "struct" -Objekts, die sie ausführen können.

Zum Beispiel:

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

Manchmal in C benötigen Sie eine Funktion aufrufen, ohne deren Umsetzung im Voraus zu kennen. Z.B. wenn Sie eine eigenständige Bibliothek entwickeln, die in verschiedenen Projekten verwendet wird. In diesem Fall ist es sinnvoll, einen Funktionszeiger zu einer Kontextstruktur hinzuzufügen und diese an die Bibliotheksfunktionen weiterzugeben. Die Bibliotheksfunktionen können dann Ihre Funktion zur Laufzeit aufrufen, ohne die Header-Dateien einschließen zu müssen, die sie definieren.

Es ist in der Tat ähnlich wie bei objektorientierten Programmierung. In C übergeben Sie normalerweise Kontextvariablen, z. eine Struktur, die eine Menge von Variablen und möglicherweise für diesen Kontext sinnvolle Funktionen zusammenfasst. Dies ist nahe an der eqvuivalent in OO-Programmierung, wo Sie eine Klasse instanziieren und die erforderlichen Variablen für die Instanz festlegen.

2

Ich habe dies in der Vergangenheit verwendet, um generische Container in C zu implementieren.

Zum Beispiel:

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; 

Die Listenstruktur selbst ist datenunabhängig, void * mit Datenelemente darstellen, und die Delegierten aller Art-aware-Operationen auf die durch die Zeiger angezeigt Funktionen oben:

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. Für geeignet lose Definitionen von "generic" und "Container"

+0

Ausgezeichnete Verwendung ... Danke –

1

Hier ist ein Projekt, um die Nützlichkeit von Funktionszeigern zu erklären. Versuchen Sie, eine c-basierte Bibliothek zu erstellen, die Vererbung und Polymorphismus bietet. Oder versuchen Sie "C with Classes" neu zu erstellen. Funktionszeiger in Strukturen sind von entscheidender Bedeutung. http://www.cs.rit.edu/~ats/books/ooc.pdf

+0

Dies war eine ausgezeichnete Referenz ... Vielen Dank! –