構造体内に関数を作成しようとしていますが、これまでのところ次のコードがあります:
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:24:2:エラー:予想される「:」、「、」、「;」、「}」または「属性 '' {'トークンの前。
正しい方法はどれですか?
直接行うことはできませんが、関数ポインターを使用して「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の多くは表示されません。
他の人が指摘したように、関数ポインターを構造内に直接埋め込むことは、通常、コールバック関数のような特別な目的のために予約されています。
おそらく必要なのは、仮想メソッドテーブルのようなものです。
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デバイスドライバーインターフェイスにもこのようなレイヤーがあります。
これはC++でのみ機能します。構造体の関数はCの機能ではありません。
Client.AddClient()についても同様です。 call ...これは、オブジェクト指向プログラミング、つまり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);
}
これはどう?
#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;
}
構造に従ってコードをグループ化しようとしています。 Cのグループ化はファイルごとです。すべての関数と内部変数をヘッダーまたはヘッダーとcソースファイルからコンパイルされたオブジェクト「.o」ファイルに入れます。
オブジェクト指向言語ではないCプログラムでは、オブジェクト指向をゼロから作り直す必要はありません。
これは前に見たことがあります。奇妙なことです。一部のコーダーは、変更したいオブジェクトを、それを変更するための標準的な方法ですが、変更する関数に渡すことを嫌います。
クラスオブジェクトが常にメンバー関数の最初のパラメーターであるという事実を隠したが、隠されているため、私はC++を非難します。そのため、オブジェクトが関数に渡されているように見えますが、そうではありません。
Client.addClient(Client& c); // addClient first parameter is actually
// "this", a pointer to the Client object.
Cは柔軟性があり、参照によって渡すことができます。
C関数は多くの場合、ステータスバイトまたはintのみを返しますが、これは多くの場合無視されます。あなたの場合、適切な形式は
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にあります