7

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

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

上記のコードでは、2番目の方法もより穏やかで非常に単純だと思います。最初の方法では、構造体のメンバーで &varあっても、まだ合格する必要があります。fun()

関数ポインタを構造体定義内に保持するのが良い場合は、理由を説明するのを手伝ってください。

4

6 に答える 6

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=fun1;
        else
          var.f=fun2;
        usevar(var);
    }

これにより、単一の呼び出しインターフェイスを使用できますが、テストが有効かどうかに応じて2つの異なる関数を呼び出すことができます。

于 2012-10-19T10:14:14.283 に答える
10

ある種の「オブジェクトベース」プログラミングを行おうとしている場合に便利です。

Quake 3エンジンのソースコードを見たことがあれば、ほとんどの「エンティティ」がそれらを定義する属性と、それらが行う作業[関数ポインタ]を持っていることがはっきりとわかります。

属性と関数を(Cの関数ポインターを介して)分離すると、「構造体」オブジェクトの属性とそれらが実行できるアクションが定義されます。

例えば:

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;
}
于 2012-10-19T10:20:26.757 に答える
2

私は過去にこれを使用して、Cでジェネリックコンテナー1を実装しました。

例えば:

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.「ジェネリック」と「コンテナ」の適切に緩い定義の場合

于 2012-10-19T12:40:59.837 に答える
1

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

例えば

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

于 2012-10-19T10:19:03.950 に答える
1

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

これは、オブジェクト指向プログラミングを行うときに行うことと実際に似ています。Cでは、通常、構造体などのコンテキスト変数を渡し、一連の変数と、場合によってはそのコンテキストにとって意味のある関数をグループ化します。これは、クラスをインスタンス化し、インスタンスに必要な変数を設定するオブジェクト指向プログラミングの同等のものに近いものです。

于 2012-10-19T10:22:04.503 に答える
1

これは、関数ポインタの有用性を説明するのに役立つプロジェクトです。継承とポリモーフィズムを提供するcベースのライブラリを作成してみてください。または、「CwithClasses」を再作成してみてください。構造内の関数ポインタは非常に重要です。http://www.cs.rit.edu/~ats/books/ooc.pdf

于 2012-10-19T12:47:43.220 に答える