51

dlsym() によって返された void ポインターがあります。void ポインターが指す関数を呼び出したいと思います。したがって、キャストして型変換を行います。

void *gptr = dlsym(some symbol..) ;
typedef void (*fptr)();
fptr my_fptr = static_cast<fptr>(gptr) ;

私も試してみreinterpret_castましたが、うまくいきませんでしたが、C キャスト演算子は機能しているようです..

4

8 に答える 8

60

void*C++98/03 では、a を関数ポインタに直接変換することはできません (キャストを使用してコンパイルしないでください)。これは、C++0x で条件付きでサポートされています (実装は動作を定義することを選択でき、それを定義する場合は、標準が行うべきであると述べていることを実行する必要がありますvoid*。C++98/03 標準で定義されているA )。 、オブジェクトを指すことを意図しており、関数ポインターまたはメンバーポインターを含めることは意図されていませんでした。

あなたがしていることは実装に大きく依存していることを知っているlong longので、標準に従って明らかに未定義の動作であっても、ほとんどのプラットフォームでコンパイルして動作するはずのオプションを 1 つ示します (32 ビット ポインターを想定し、64 ビットで使用します)。

void *gptr = dlsym(some symbol..) ;
typedef void (*fptr)();
fptr my_fptr = reinterpret_cast<fptr>(reinterpret_cast<long>(gptr)) ;

そして、コンパイルして動作するはずの別のオプションがありますが、上記と同じ注意事項があります。

fptr my_ptr = 0;
reinterpret_cast<void*&>(my_ptr) = gptr; 

それともスローモーションで...

// get the address which is an object pointer
void (**object_ptr)() = &my_ptr;  

// convert it to void** which is also an object pointer
void ** ppv = reinterpret_cast<void**>(object_ptr);

// assign the address in the memory cell named by 'gptr' 
// to the memory cell that is named by 'my_ptr' which is
// the same memory cell that is pointed to 
// by the memory cell that is named by 'ppv'
*ppv = gptr;  

これは基本的に、関数ポインタのアドレスがオブジェクト ポインタ ( void (**object_ptr)())であるという事実を利用reinterpret_castしているため、 などの他のオブジェクト ポインタに変換するために使用できますvoid**。その後、( を逆参照することによって) アドレスをvoid**実際の関数ポインターまでたどり、そこに gptr の値を格納することができます。

yuk - 決して明確に定義されたコードではありませんが、ほとんどの実装で期待どおりに動作するはずです。

于 2009-07-08T06:10:58.063 に答える
2

引数リストが何であるかを知っていれば、それを c-cast するのは非常に簡単です。上記のように、未定義の動作がありますが、ペット プロジェクトのイベント ハンドラーでこれを使用しており、msvc で問題なく動作しているようです。
同じ void* を _beginthread_proc_type にキャストして _beginthread でスレッドを開始することもできますが、それによって問題が発生することもないようです (ただし、引数を必要としない関数に引数を送信した場合の結果についてはよくわかりません)。 、または引数を必要とする関数に引数を送信しないことで十分です。これは、少なくとも関数を呼び出したり、私の限られたテストでスレッドを開始したりするようです)

void somefunction(){
    std::cout <<"hi"<<std::endl;
}

void* function = (void*)&somefunction;
((void(__cdecl*)(void))(function)) ();

_beginthread((_beginthread_proc_type)function, 0, NULL);

コミュニティがマクロに対する嫌悪感を募らせていることは知っていますが、私はイベント ハンドラーでその関数呼び出しにマクロを使用しています。

#define call_voidstar_function(fc)     ((void(__cdecl*)(void))(fc)) ()
于 2020-11-05T05:35:51.720 に答える
1

これは、再解釈キャストを使用せずに Visual Studio でコンパイルします。

void *ptr;
int (*func)(void) = (int(*)(void))ptr;
int num = func();
于 2011-11-20T01:51:55.323 に答える
-4

これはあなたを助けるかもしれません。「こんにちは」と表示されます。

#include <iostream>

void hello()
{
  std::cout << "Hello" << std::endl;
}

int main() {
  typedef void (*fptr)();
  fptr gptr = (fptr) (void *) &hello;
  gptr();
}

または、次のことができます。

fptr gptr = reinterpret_cast<fptr>( (void *) &hello);

&hello は dlsym コマンドに置き換えられます。

于 2009-07-08T06:15:48.410 に答える