void * to pointer - PullRequest
       2

void * to pointer

2 голосов
/ 21 мая 2011

Обычно при вызове динамически загруженной функции я обычно выполняю стандартное прямое приведение:

typedef int (*GenericFn)(); // matches x86 FARPROC, minus explicit calling convention
typedef bool (*DesiredFn)(int,int);

GenericFn address = GetProcAddress(module, "MyFunction");
DesiredFn target = reinterpret_cast<DesiredFn>(address);

Сегодня я сделал что-то немного другое (и мозговой покой).

DesiredFn target = nullptr;

void* temp = static_cast<void*>(&target); // pointer to function pointer
GenericFn* address = static_cast<GenericFn*>(temp);
*address = GetProcAddress(module, "MyFunction"); // supposedly valid?

// temp is declared void* because a void** cannot be cast to GenericFn* without
// first doing a void** -> void* conversion

assert(target == MyFunction); // true on VC10, presumably GCC

Мои вопросы:

  1. Хорошо ли определено поведение void* (примечание: , а не a void**) для типа указателя объекта?
  2. Почему компилятор допускает static_cast<void*> на void**?
  3. Почему я настолько глуп, чтобы попробовать это?
  4. Видите ли вы что-нибудь еще, что не так с этим примером?

С тех пор я решил снова использовать метод # 1 из-за ясности кода (и потому что я знаю, что он должен работать). Я до сих пор интересуюсь, почему метод № 2 сработал:).


На случай, если вам интересно (о моем объяснении)

Сегодня я удалил <windows.h> зависимости в нескольких общедоступных интерфейсах, и вместо того, чтобы переопределять FARPROC, как я должен был, я экспериментально изменил свою функцию FARPROC возвращаемого типа, чтобы вместо нее принять выходной параметр void* (I знаете, это должно было быть void**).

// implemented in some library cpp file
void detail::FunctionResolve(std::string export, void* output)
{
    FARPROC* address = static_cast<FARPROC*>(output);
    *address = GetProcAddress(...);
}

// header-defined interface class
template<typename F>
class RuntimeFunction {
    F* target;

    void SetFunction(std::string export) {
        // old: this->target = reinterpret_cast<F*>(detail::FunctionResolve(...));
        // new:
        detail::FunctionResolve(export, static_cast<void*>(&this->target));
    }
};

Ответы [ 2 ]

1 голос
/ 21 мая 2011
typedef int (*GenericFn)(); // matches x86 FARPROC, minus explicit calling convention
typedef bool (*DesiredFn)(int,int);

DesiredFn target = nullptr;

void* temp = static_cast<void*>(&target); // pointer to function pointer

Здесь нет ничего плохого, но приведение не нужно. Указатель на любой объект (указатель на функцию является объектом) может быть преобразован в указатель на void без приведения. например,

void* temp = &target;

GenericFn* address = static_cast<GenericFn*>(temp);

Вы можете преобразовать указатель в void в указатель на любой тип объекта, но результаты будут определены, только если вы приведете значение, преобразованное в void*, к исходному типу, из которого оно было преобразовано. Технически, только static_cast<DesiredFn*>(temp) будет иметь четко определенный результат.

*address = GetProcAddress(module, "MyFunction"); // supposedly valid?

Это технически неверно, поскольку вы солгали о типе значения, которое вы присвоили address, поэтому address не указывает на объект, который соответствует его информации о типе.

Сказав все это, во многих реализациях все указатели функций представлены одинаково, и любое приведение и преобразования не влияют на значение, которое фактически сохраняется. Пока вы вызываете функцию через указатель, который фактически соответствует типу указателя, у вас не будет никаких проблем.

В конце концов, вы должны полагаться на поведение вашей реализации reinterpret_cast и GetProcAddress, чтобы оригинальный метод вообще работал, но - как вы говорите - я бы рекомендовал придерживаться подхода reinterpret_cast в этом случае как понятно, что происходит.

1 голос
/ 21 мая 2011

Это не имеет значения, потому что void * и void ** имеют одинаковый размер.Вы просто меняете тип.Почему бы просто не привести к нужному типу?

DesiredFn target = 
    reinterpret_cast<DesiredFn>(GetProcAddress(module, "MyFunction"));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...