3

質問: C++ でメンバ関数へのポインタを intptr_t にキャストする方法はありますか?

既知の要因:

  1. メンバー関数ポインターが非常に特別なものであることは知っています
  2. メンバー関数が非表示の「this」パラメーター (__thiscall) を渡すことはわかっています。
  3. 場合によっては sizeof(member function pointer) > sizeof(intptr_t) であることを知っています。この質問では、可能な場合についてのみ話しています。つまり、私の場合は sizeof(member function pointer) == sizeof(intptr_t) です。 .
  4. 最後に、ポインターを intptr_t にキャストするのは適切なパターンではないことがわかりました。

サンプルコード:

class test // No inheritance, in the case I need
    {
    public:
    void func();    // No virtual, or any special modifiers in the case I need
    };

void main2()
    {
    intptr_t p = &test::func;
    };

このキャストを行うための回避策は知っていますが、一時変数を要求するため、好きではありません。

void my_way()
    {
    intptr_t p;
    auto t = &test::func;       // Temp variable, I don't like the fact I need to use it, but I have no other way for now
    p = *reinterpret_cast<intptr_t*>(&t);
    };

したがって、問題は、一時変数を使用せずに (同じ memcpy を使用せずに)、右辺値式としてインラインでトリックを実行する方法です。

例:

reinterpret_cast<??>(???_cast<??>(???_cast<??>( &test::func )))

(表現が綺麗になるかどうかは気にしません)。

-------------------------(質問ではなく理由についてのいくつかの考えの下に)-------------- ------------------

このサイトには似たようなテーマがいくつかありますが、それらのほとんどは「なぜそうするのですか?」または「なぜこれが必要なのですか?」について話しています。自分。

このスタッフが必要な理由: 動的リンク用の独自のメカニズムを実装することを決定したある種のタスクを書いています。いくつかの特定のアプリケーションが存在する可能性があります。

私の場合 - 動的リンケージ機構 - 関数へのポインタを別のモジュールに渡したいです。私はクラスとインターフェースを別の構造として持っています(同じアプローチのライブラリがあることは知っています)。このメカニズムを使用するすべてのクラスはプレーンであることが知られています (継承がまったくないため、仮想クラスなどはありません)。これはすべて、MSVC 2012 によってコンパイルされた x86 32 ビット、または最大で 64 Windows で実行されます。インターフェイスはクラスから完全に分離されているため、ポインターの配列を使用します。Lib は配列をホスト プロセスに渡します。ホストプロセスにはこれがあります...「問題」ではありませんが、それでも:

inline int my_interface::func_name(int param)
    {
    decltype(&interface_name::func_name) temp;
    *((intptr_t*)&temp) = reinterpret_cast<interface_name::funcs*>(interface_desc->funcs)->func_name;
    return (reinterpret_cast<decltype(this)>(object)->*temp)(param);
    };

これはインライン関数なので、できるだけ小さくしたいのですが、可能であれば「temp」を削除したいと考えています。これは、すべての最適化を行っても、コンパイラがこれを正しく削除できるかどうかわからないためです。

その他のアプリケーション (仮説的): - メンバー関数が存在するメモリ ページを特定のガードで保護したい場合。WinAPI はそうする方法を提供してくれますが、ページのアドレスが必要です。通常の機能ではこれを行うのに問題はありませんが、メンバーの場合 - 私が説明した WA のみですか? それとも方法がありますか?- 実行時にイメージにパッチを適用したい場合はどうすればよいですか? つまり、いくつかの const を見つけて別の const に置き換えるには?ランタイム パッチを適用する理由は、少なくともいくつか考えられます: 2.1 動的リンケージ再配置プロセス、2.2 コードの難読化。

これは単なるメモです - 読者はしばしば「何のために」と尋ねます。理由については議論したくありません。なぜなら、私の意見では、多くのアプリケーションがあり、それらはすべて初心者向けではなく、セキュリティ担当者向けなどです...

「なぜそうするのですか?」、「dll/boost/他のライブラリ/他の言語に既存のメカニズムを使用しないのはなぜですか?」については議論しないでください。このスレッドで。

4

1 に答える 1

2

いいえ、仕様では、関数ポインターまたはメンバー ポインターを intptr_t にキャストすることはできません。その理由は、それらを記述するために複数の intptr_t 分のデータが必要になる場合があるためです。たとえば、gcc のメンバー ポインターは 3 intptr_t の長さであり、MSCV の範囲は 1 ~ 4 intptr_t の長さです。これの多くは、仮想機能を処理するために使用されます。

一部の古いハードウェア (C++ がサポートする) では、ポインターは実際には関数ポインターよりも小さくなります。これは、8 ビットのメモリ構造を指すだけでよい小規模なシステムで発生しますが、プログラムは 16 ビットのプログラム メモリ空間にロードされます。

多くの場合、使用しようとしているこのパターンはデリゲート (特定のオブジェクトに永続的に結び付けられたメンバー関数ポインター) の作成に使用されます。これは、2 つの int ポインターとラッピング関数で実行できます。

struct Delegate
{
    intptr_t   obj;  // I'll use intptr_t here, but often this is void*
    intptr_t   func;
};

// you need one of these for each type of mfp you use
static void callT_Test(intptr_t obj)
{
    T* realObj = reinterpret_cast<T*>(obj);
    realObj->test();
}

// constructing a delegate to call test on t
Delegate d;
d.obj = reinterpret_cast<intptr_t>(&t);
d.func = &callT_Test;
于 2013-09-15T19:09:43.900 に答える