2012-10-19 8 views
7

私はCプログラミングの新人ではありません。しかし、私はポインタがCの構造メンバーとして機能するようにする有用性が何であるか分かりません。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);  
    } 

は、プログラマがCコードにオブジェクト指向(OO)形状を与え、抽象オブジェクトを提供するために、それを使用していますか?コードを技術的に見せることもできます。

私は、上記のコードでは、第2の方法はやさしく簡単だと思います。最初の方法では、我々はまだ&varを渡さなければならず、さらにfun()はstructのメンバです。

関数のポインタを構造体の定義内に保つことが良いのであれば、その理由を説明するのを助けてください。

+2

C++クラスの仮想関数について考える。彼らは同様の方法で実装されています。 –

+2

[組み込みシステムの関数ポインタについて](http://stackoverflow.com/questions/4836245/function-pointers-in-embedded-systems-are-the-useful)。 – Lundin

+0

ありがとう@Lundin!私がそこで見つけた本当に非常に有用で興味深い答え。 –

答えて

11

構造体上の関数へのポインタを提供すると、構造体上で実行する関数を動的に選択することができます。

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

これはあなたに一つだけのコードを維持する能力を与え、2つの異なる機能を呼び出すことではなく、あなたのテストが有効であるかどうか。

+0

これはすべてだと思っています... C++(実行時またはコンパイルバインド)で多態性と呼ばれる –

1

これは、組み込みシステムやドライバの作成に特に役立ちます。 関数は、関数ポインタを使用して呼び出されます。


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

など

10

その耐用あなたはプログラミング「ベースのオブジェクト」のいくつかの並べ替えをしようとしている場合。

Quake 3エンジンのソースコードを見たことがあれば、ほとんどの「エンティティ」にはそれらを定義する属性と、それらが行う機能[関数ポインタ]が明確に分かります。

属性と関数を(Cの関数ポインタを介して)分離することで、 "struct"オブジェクトの属性とアクションを定義できます。例えば

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

は時々Cであなたがその実装の先行を知らなくても、関数を呼び出す必要があります。例えば。異なるプロジェクトで使用されるスタンドアロンのライブラリを開発している場合その場合、コンテキスト構造体への関数ポインタを追加し、それをライブラリ関数に渡すことは理にかなっています。ライブラリ関数は、それを定義するヘッダファイルをインクルードしなくても、実行時に関数を呼び出すことができます。

実際には、オブジェクト指向プログラミングを行うときと同じです。 Cでは、通常、コンテキスト変数を渡します。構造体は、変数のセットと、おそらくそのコンテキストに意味のある関数をグループ化します。これは、OOプログラミングのeqvuvalentに近く、クラスをインスタンス化し、インスタンスに必要な変数を設定します。

2

これまで、ジェネリックコンテナをCで実装するためにこれを使用しました。例えば

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; 

リスト構造自体はデータ項目を表すためにvoid *を使用して、データに依存しないで、上記ポインタによって示される機能に委譲すべてのタイプの認識動作を:

適当に緩い定義について
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. "汎用" と "コンテナ"

+0

優秀な使用...ありがとう –

1

ここには、関数ポインタの有用性を説明するためのプロジェクトがあります。継承と多型を提供するCベースのライブラリを作成してみてください。または、「Cクラス」を再作成してみてください。構造内の関数ポインタは重要です。 http://www.cs.rit.edu/~ats/books/ooc.pdf

+0

これは素晴らしい参考文献でした...ありがとう! –

関連する問題