2013-06-11 19 views
49

イムこれまでのところ、私はこのコードを持って、構造の内部関数を作成しようとしている:C - 構造体の内部の機能

typedef struct client_t client_t, *pno; 
struct client_t 
{ 
     pid_t pid; 
     char password[TAM_MAX]; // -> 50 chars 
     pno next; 

     pno AddClient() 

     { 
      /* code */ 
     } 

}; 

int main() 
{ 

    client_t client; 

    //code .. 

    client.AddClient(); 

} 

エラーclient.h:2:24エラー:予想「: '、'、 '、'; '、'} 'または' 属性 'の前に' {'トークン。

正しい方法はありますか?

+9

だろうかもしれません。あなたは関数ポインタによってそれを大まかにシミュレートしようとすることができます。 – Fingolfin

+1

関数ポインタは代用可能ですか? http://stackoverflow.com/a/840703/635678 –

答えて

71

それは、直接実行することはできませんが、あなたは関数ポインタを使用して同じことをエミュレートし、明示的にすることができます"this"パラメータを渡します:

typedef struct client_t client_t, *pno; 
struct client_t 
{ 
     pid_t pid; 
     char password[TAM_MAX]; // -> 50 chars 
     pno next; 

     pno (*AddClient)(client_t *);  
}; 

pno client_t_AddClient(client_t *self) { /* code */ } 

int main() 
{ 

    client_t client; 
    client.AddClient = client_t_AddClient; // probably really done in some init fn 

    //code .. 

    client.AddClient(&client); 

} 

しかし、これを行うことは本当にあなたにひどいものを買わないことがわかります。このように、このスタイルでは多くのC APIが実装されているわけではありません。外部関数を呼び出してインスタンスを渡すだけでよいからです。

+1

ありがとう、先生 – amanuel2

+1

X11 APIは、このような何かをします。 [XImage](https://en.wikipedia.org/wiki/XImage)を参照してください。 Windows APIの下にある – Hydranix

+0

のコードはそれでいっぱいです。技術的には、「ウィンドウクラス」は、2つのコールバック関数ポインタとオープンエンドを持つ構造体です(登録時に指定できる「ウィンドウクラス仕様データ」の場合) – Swift

10

これはC++でのみ動作します。構造体の関数はCの機能ではありません。

同じことがあなたのclient.AddClient()にあります。これはオブジェクト指向プログラミング、すなわちC++であるメンバー関数の呼び出しです。

ソースを.cppファイルに変換し、それに応じてコンパイルしていることを確認してください。

あなたがCに固執する必要がある場合は、以下のコードは、(一種の)と同等です:

typedef struct client_t client_t, *pno; 
struct client_t 
{ 
     pid_t pid; 
     char password[TAM_MAX]; // -> 50 chars 
     pno next; 

}; 


pno AddClient(pno *pclient) 
{ 
    /* code */ 
} 


int main() 
{ 

    client_t client; 

    //code .. 

    AddClient(client); 

} 
+0

これは単一のプロジェクトで、私はCを使用する必要があります。私はC言語で欲しいものを磨くことができる方法はありますか? – xRed

+0

その関数を構造体の外に移動し、インスタンスへのポインタを受け入れるようにしてください。 –

+0

複雑な魔法を使わなければ、client.AddClient()はできません(他の答えを参照)。 – QSQ

18

他にも触れたように、構造体の内部に関数ポインタを埋め込むことは、通常、コールバック関数のような特別な目的のために予約されています。

仮想メソッドテーブルのようなものでしょう。

typedef struct client_ops_t client_ops_t; 
typedef struct client_t client_t, *pno; 

struct client_t { 
    /* ... */ 
    client_ops_t *ops; 
}; 

struct client_ops_t { 
    pno (*AddClient)(client_t *); 
    pno (*RemoveClient)(client_t *); 
}; 

pno AddClient (client_t *client) { return client->ops->AddClient(client); } 
pno RemoveClient (client_t *client) { return client->ops->RemoveClient(client); } 

さて、以上の操作を追加することclient_t構造体のサイズを変更しません。さて、この種の柔軟性は、多くの種類のクライアントを定義する必要がある場合や、操作の振る舞いを拡張できるようにするために、client_tインターフェースのユーザーが許可したい場合にのみ便利です。

この種の構造は実際のコードで表示されます。 OpenSSL BIOレイヤーはこれに似ていますが、UNIXデバイスドライバインターフェイスもこのようなレイヤーを持っています。

+0

関連項目[dynamic dispatch](http://stackoverflow.com/a/17622474/315052)。 – jxh

4

これはいかがですか?

#include <stdio.h> 

typedef struct hello { 
    int (*someFunction)(); 
} hello; 

int foo() { 
    return 0; 
} 

hello Hello() { 
    struct hello aHello; 
    aHello.someFunction = &foo; 
    return aHello; 
} 

int main() 
{ 
    struct hello aHello = Hello(); 
    printf("Print hello: %d\n", aHello.someFunction()); 

    return 0; 
} 
+0

JavaScripのような「ちょっとした」ビットソリューション –

0

structに基づいてコードをグループ化しようとしています。 Cグループはファイル単位です。 すべての関数と内部変数をヘッダに入れます。 ヘッダとオブジェクトファイル ".o"をcソースファイルからコンパイルします。

オブジェクト指向言語ではないCプログラムの場合は、オブジェクト指向をゼロから再作成する必要はありません。

私は以前これを見ました。 これは奇妙なことです。コーダーの中には、標準的な方法であっても、変更したいオブジェクトを関数に渡すことを嫌うものがあります。

私は、クラスオブジェクトが常にメンバ関数の最初のパラメータであるが、それは隠されているという事実を隠しているので、C++を責めます。だから、たとえそれがオブジェクトであっても、関数にオブジェクトを渡していないように見えます。

Client.addClient(Client& c); // addClient first parameter is actually 
          // "this", a pointer to the Client object. 

Cは柔軟であり、参照することによって物事を通過することができます。

C関数はステータスバイトまたはintのみを返すことが多く、それはしばしば無視されます。 あなたのケースでは、適切なフォームでは、C言語で構造体の機能を持つことはできません

err = addClient(container_t cnt, client_t c); 
if (err != 0) 
    { fprintf(stderr, "could not add client (%d) \n", err); 

addClientがClient.hかいるclient.c

関連する問題