2009-07-08 4 views
28

У меня есть указатель на void, возвращаемый dlsym(), я хочу вызвать функцию, указанную указателем void. Так что я преобразование типа литьем:Назначение указателей функций в C++

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

Я также попытался reinterpret_cast, но не повезло, хотя оператор C литая, кажется, работает ..

+0

тьфу, ваше форматирование имеют беспорядок. –

+0

Вам действительно нужно исправить этот код, чтобы мы могли его прочитать. Что с чертой? Вы пытаетесь ввести my_fptr = static_cast (gptr)? –

+1

Исправлена ​​проблема форматирования. Вместо использования тегов HTML используйте доступные кнопки форматирования. – Naveen

ответ

45

Преобразование void* к указателю функции непосредственно (не следует компилировать с использованием каких-либо приведений) в C++ 98/03. Он условно поддерживается в C++ 0x (реализация может выбрать определение поведения, и если он ее определит, то он должен делать то, что говорит стандарт. A void*, как определено стандартом C++ 98/03 , предназначалось для обозначения объектов и не содержать указателей на функции или указателей элементов.

Зная, что то, что вы делаете, зависит от реализации, вот один из вариантов, который должен компилироваться и работать (при условии, что 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 - отнюдь не определенный код - но он должен делать то, что вы ожидаете от него в большинстве реализаций.

+1

Я ожидаю, что это все - кастинг C++ является стандартно-совместимым, C casting обратно совместим с требованиями вызовов общей библиотеки POSIX. –

+0

Даже явное приведение в стиле C не требуется для преобразования или даже компиляции - приведение стиля C определяется с точки зрения других приведений (с одной незначительной дополнительной функцией, касающейся доступности базового класса). –

+7

В качестве примечания, лучший выбор типа для промежуточного литья может быть 'size_t' - он обычно достаточно велик, чтобы соответствовать указателю на любой платформе, хотя это также не гарантируется. Еще лучше, используйте ''/'' header и 'intptr_t' typedef в нем, где он доступен (C99, C++ TR1, C++ 0x). –

-6

Это может вам помочь. Он печатает «Привет».

#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); 

где & привет заменяется командой dlsym.

+1

Я буду удивлен * если это полезно! –

+0

Причина, по которой вы работаете, заключается в том, что вы не используете указатель 'void *'. –

+1

После редактирования он, верно? И код, похоже, работает. (Хотя я не эксперт, так что, возможно, это работает, но на самом деле не определено?) – Mike

2

компилируется в Visual Studio без использования переосмысливать бросание:

void *ptr; 
int (*func)(void) = (int(*)(void))ptr; 
int num = func(); 
+2

Может компилироваться, но ** будет ** приводить к неопределенному поведению (как описано в спецификациях C.) –

+2

Действительно ли это без ' reinterpret_cast'? Какой кастинг будет выбран компилятором? –

+5

Вы делаете приведение в стиле c, которое в этом случае является эффектом реинтерпрета. – WestleyArgentum

0

Я нашел (немного уродливый) решение. 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; 
} 
+0

Это работает, если единица компиляции C, но не C++ 11 и позже, поскольку это неопределенное поведение: http://stackoverflow.com/questions/11373203/accessing-inactive-union-member-undefined-behavior – Vitali

5

Заметим, что C++ 11 позволяет такое преобразование и от GCC 4.9 и выше этого преобразования не генерирует предупреждение: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57869.

См SO обсуждения:

Смежные вопросы