web-dev-qa-db-ja.com

C ++でキャストする関数ポインター

Dlsym()によって返されるvoidポインターがあり、voidポインターが指す関数を呼び出したい。だから私はキャストして型変換を行います:

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

私も試してみましたreinterpret_castしかし運はありませんが、Cキャスト演算子は機能しているようです。

37
sud03r

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

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

_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-決して明確に定義されたコードではありません-しかし、それはほとんどの実装で期待することをするはずです。

49
Faisal Vali
8
Amir Kirsh

私はこの(少しい)ソリューションを見つけました。最大警告レベルのgccは文句を言いません。この例では、dlsym()(void *を返す)を呼び出し、関数ポインターで結果を返します。

typedef void (*FUNPTR)();

FUNPTR fun_dlsym(void* handle, const char* name) {
    union {
        void* ptr;
        FUNPTR fptr;
    } u;
    u.ptr = dlsym(handle, name);
    return u.fptr;
}
1
BrunoLevy

次の手法を使用できます。

int (*fn)(int);
*(void **)(&fn) = dlsym(lib1, "function");
int result = (*fn)(3);

または

fn = (int (*)(int))dlsym(lib1, "function");

コンパイル済み:

g++ -Wall -pedantic -std=c++11
0
Yura

dlsymを、必要なポインターを返す関数にキャストして、次のように呼び出すことができます。

typedef void (*fptr)();
fptr my_fptr = reinterpret_cast<fptr (*)(void*, const char*)>(dlsym)(RTLD_DEFAULT, name);

PS。関数ポインターを別の関数ポインターにキャストしてから呼び出すのは未定義の動作です( https://en.cppreference.com/w/cpp/language/reinterpret_cast のポイント7を参照) dlsymの結果をuintptr_tにキャストしてから、必要なタイプにキャストするには:

fptr my_fptr = reinterpret_cast<fptr>(reinterpret_cast<uintptr_t>(dlsym(RTLD_DEFAULT, name)));
0

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

void *ptr;
int (*func)(void) = (int(*)(void))ptr;
int num = func();
0
Andrew Best