BT

最新技術を追い求めるデベロッパのための情報コミュニティ

寄稿

Topics

地域を選ぶ

InfoQ ホームページ ニュース C#機能: 静的デリゲートと関数ポインター

C#機能: 静的デリゲートと関数ポインター

原文(投稿日:2019/02/06)へのリンク

C#のリリースごとに低レベルの機能が追加される。ほとんどのビジネスアプリケーション開発者には不要だが、グラフィック処理、機械学習、数学的パッケージに適したハイパフォーマンスのコードを可能にする。

以下の2つの提案は、関数の参照と実行に対する新しい方法である。

静的デリゲート

C#の通常のデリゲートはやや複雑なデータ構造である。これには関数ポインター、thisポインターパラメータへのオプションのオブジェクト参照、連鎖したデリゲートへのリンクが含まれる。構造の全体には、ヒープに割り当てられた他の参照型と同様に、対応するメモリ負荷がある。さらにアンマネージドコードと一緒に使用する場合は、マーシャリングされる必要がある。

通常のデリゲートと比較して「静的デリゲート」は非常にシンプル化されている。1つのフィールド、IntPtr型の関数ポインターを持つ構造体として実装されている。これはblittable、つまりマネージドコードとアンマネージドコードを使ったときに、完全に同じメモリレイアウトになる。つまりネイティブシステム関数を呼び出す時にマーシャリングが必要ないということである。

これは次の構文で宣言される:

static delegate int Func()

UnmanagedFunctionPointer属性と同様の属性を使用して、文字セットや呼び出し規約などの追加設定ができる。

静的デリゲートには制限がないわけではない。これらは静的関数のみを参照できる。それらはオブジェクトへのポインタを格納していないため、オブジェクトのメンバーメソッドは許可されていない。さらに静的デリゲートは他のデリゲートへのチェーンはできない。

CLRレベルはで、静的デリゲートはcalli (call indirect)命令を使って呼び出される。対照的に、通常のデリゲートはcallまたはcallvirt (call virtual)命令を使って呼び出される。

既存コードとの互換性を高めるために、静的デリゲートから通常デリゲートへの暗示的な変換が許可されている通常デリゲートは静的デリゲートの要件を満たしているとは限らないので、逆方向は明示的なキャストが必要である。

詳細はGitHubの静的デリゲート提案で読むことができる。

関数ポインター

競合する提案は単純に関数ポインターと呼ばれている。これもcalli命令とそのパートナーであるldftn (load method pointer) 命令を使って機能を公開する。前の提案と同様に、これはデリゲート宣言から始まる。このケースではdelegateキーワードはfuncptrに置き換えられる。

funcptr int F1(int value);

ネイティブ関数を呼び出す時、呼び出し元は呼び出し規約がなんであるかを知っている必要がある。これはスタック上のアイテムの順序や、呼び出し元と呼び出し先のどちらが使用後のスタックをクリアする責任があるかなどに影響する。この提案でカバーされている呼び出し規約は、cdecl, fastcall, stdcall, thiscall, winapiである。開発者はデリゲートの宣言を変更することによってどれを使用するかを指定できる:

funcptr cdecl int F1(int value);

提案では、関数ポインターはunsafeコンテキストのみで利用できる。

この提案では、関数ポインターを作成するために、関数名にaddress-ofオペレータ(&)を使用できる。これもまたunsafeコンテキストでのみ使用できる。

関数ポインターのその他の制限は、静的デリゲートと同様である。静的関数のみが参照でき、他のデリゲートにチェーンできない。

どちらの提案も検討中で、C#のロードマップにはまだ含まれていない。Compiler Intrinsicsという名前の第3の提案がこれら2つと競合するが、魅力的でない追加の制限がある。

この記事に星をつける

おすすめ度
スタイル

BT