C-構造体内の関数


86

構造内に関数を作成しようとしていますが、これまでのところ、次のコードがあります。

エラーclient.h:24:2:エラー:'{'トークンの前に ' :'、 '、'、 ';'、 '}'または '属性'が必要です。

それを行う正しい方法はどれですか?


12
Cの構造体に関数を含めることはできません。ただし、関数ポインタを使用して大まかにシミュレートすることはできます。
フィンゴルフィン

1
関数ポインタは許容できる代替物ですか? stackoverflow.com/a/840703/635678
Dan O

回答:


108

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

ただし、これを行っても、それほど多くのことを購入することにはなりません。そのため、外部関数を呼び出してインスタンスを渡すだけでもよいため、このスタイルで実装されたCAPIはあまり見られません。


3
X11APIはこのようなことをします。XImageを参照してください。
Hydranix 2016

1
WindowsAPIの下にあるコードはそれでいっぱいです。技術的には「ウィンドウクラス」は、2つのコールバック関数ポインタを持つと開放端を持つ構造体(「ウィンドウクラス詳細データ」そのためにあなたが登録している間に供給することができます)です
スウィフト-金曜日パイ

1
これらの手順に従いましたが、struct.function = newFunctionを実行すると、コンパイラは次のように出力します。エラー:「。」の前に「=」、「、」、「;」、「asm」または「属性」が必要です。トークン
Bonfra 2018

これは、読み取り機能と書き込み機能を備えているが、ハードドライブの種類によって異なる共通のターゲット(ハードドライブなど)が必要な場合にも役立ちます
Menotdan

実行時に実際の実装を選択すると、多くのことを購入できます。静的関数しかない場合は、関数呼び出しのたびにその関数内で常に再選択する必要があります。関数ポインターを使用する場合、選択は1回だけ行われます。また、構造体の存続期間を通じて選択を変更することもできます。
Mecki

24

他の人が指摘しているように、構造体の中に関数ポインタを直接埋め込むことは、通常、コールバック関数などの特別な目的のために予約されています。

おそらく必要なのは、仮想メソッドテーブルのようなものです。

現在、操作を追加しても、client_t構造のサイズは変更されません。現在、この種の柔軟性は、多くの種類のクライアントを定義する必要がある場合、またはclient_tインターフェイスのユーザーが操作の動作を拡張できるようにする場合にのみ役立ちます。

この種の構造は実際のコードに現れます。OpenSSL BIOレイヤーはこれに似ており、UNIXデバイスドライバーインターフェイスにもこのようなレイヤーがあります。


15

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

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

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

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


1
これはユニプロジェクトであり、Cを使用する必要があります。Cで必要なことを達成する方法はありますか?
xRed 2013年

その関数を構造体の外に移動して、インスタンスへのポインターを受け入れるようにするだけです。
user123 2013年

client.AddClient()は、少し複雑な魔法がなければ不可能です(他の回答を参照)。
QSQ 2013年

14

これはどう?


「少し」のJavaScripのようなソリューション
ビットマン2017年

8

構造体に従ってコードをグループ化しようとしています。Cグループ化はファイルごとです。すべての関数と内部変数をヘッダーまたはヘッダーと、ACソースファイルからコンパイルされたオブジェクト「.o」ファイルに配置します。

オブジェクト指向言語ではないCプログラムでは、オブジェクト指向を最初から作り直す必要はありません。

私はこれを以前に見たことがあります。不思議なことです。コーダーは、変更したいオブジェクトを関数に渡して変更することを嫌がりますが、それが標準的な方法です。

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

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

AC関数は、ステータスバイトまたはintのみを返すことが多く、それは無視されることがよくあります。あなたの場合、適切な形式は

addClientはClient.hまたはClient.cにあります


このアプローチには賛否両論があります。関数を配置する非OO()戦略とOO()戦略の両方を参照しそれが常に行われている方法であるという理由だけで、それを試すのをやめるべきだという意味ではありません。これはCが書かれた歴史的な方法ではなく、Cをこのように書く必要はないことを指摘することは完全に有効だと思います(多くの言語、特に手続き型、機能的、または論理的パラダイムからの場合も同様です)、しかし、私たちは積極的にパターンを思いとどまらせる必要はありません。それだけでなく、いくつかの利点が付属していますdo(object, subject)subject.do(object)
hiljusti

0

関数の引数として関数に構造体ポインタを渡すことができます。参照渡しと呼ばれます。

そのポインタ内の何かを変更すると、他のものはに更新されます。このようにしてみてください:


参照による受け渡しはありません。Cです。ポインターのコピーを渡しています。ポインターの参照は同じですが、ポインター自体はありません。
コルテス軍曹

訂正ありがとうございます。TutorialspointからCパスバイリファレンスチュートリアルを読みました。これは私が上で書いたものとは異なりますか?
Hadi HidayatHammurabi20年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.