Приведение указателя void (data) к указателю функции

Я знаю, что это было предложено раньше, но ни один из случаев, которые я видел здесь такой один. Я импортирую некоторые функции API во время выполнения, общее объявление этих функций будет выглядеть так:

// Masks for UnmapViewOfFile and MapViewOfFile
typedef BOOL (WINAPI *MyUnmapViewOfFile)(LPCVOID);
typedef LPVOID (WINAPI *MyMapViewOfFile)(HANDLE, DWORD, DWORD, DWORD, SIZE_T);

// Declarations
MyUnmapViewOfFile LoadedUnmapViewOfFile;
MyMapViewOfFile LoadedMapViewOfFile;

затем я вызываю общую функцию" load", где она вызывает GetProcAddress, чтобы получить адрес экспортированной функции из соответствующей DLL. Этот адрес возвращается на пустоту**. Этот void* * является одним из параметров в общей нагрузке, что-то например:

int GenericLoad(char* lib, void** Address, char* TheFunctionToLoad)

и я бы назвал эту функцию:

void *Address;
GenericLoad("kernel32.dll", &Address, "UnmapViewOfFile");
LoadedUnmapViewOfFile = (MyUnmapViewOfFile) Address;

или что-то подобное. Теперь, конечно, компилятор жалуется на попытку привести void данных* к указателю функции. Как же мне это сделать?

Я читал бесчисленные сайты и всевозможные неприятные слепки, поэтому я был бы признателен, если бы вы добавили код к объяснению.

спасибо Джесс!--4-->

3 ответов


правильным кодом будет эта строка:

GenericLoad("kernel32.dll", (void**)&LoadedUnmapViewOfFile, "UnmapViewOfFile");

то, что здесь сделано, в основном таково: адрес переменной указателя (тот, в котором вы хотите, чтобы адрес функции был помещен) передается GenericLoad - что в основном то, что он ожидает. void* * должен был обозначать "дайте мне адрес вашего указателя". Весь тип кастинга-это магия вокруг него. C не позволит указать "указатель на любой указатель функции", поэтому автор API предпочел void**.


теперь, конечно, компилятор жалуется на попытку привести пустоту данных* к указателю функции

мои компиляторы вообще не жалуются на ваш код (опять же, у меня нет предупреждений - я использую более или менее параметры по умолчанию). Это с различными компиляторами от MS, GCC и других. Можете ли вы дать более подробную информацию о компиляторе и параметрах компилятора, которые вы используете, и точное предупреждение, которое вы видите?

что сказал, C не гарантирует, что указатель функции может быть приведен к / из Указателя void без проблем, но на практике это будет работать нормально в Windows.

если вы хотите что - то, что соответствует стандартам, вам нужно будет использовать "общий" указатель функции вместо указателя void-C гарантирует, что указатель функции может быть преобразован в любой другой указатель функции и обратно без потерь, поэтому это будет работать независимо от вашей платформы. Вероятно, поэтому возвращаемое значение Win32 GetProcAddress() API возвращает FARPROC, который является просто typedef для указателя функции на функцию, которая не принимает никаких параметров (или, по крайней мере, неопределенных параметров) и возвращает указатель размера int. Что-то вроде:

typedef INT_PTR (FAR WINAPI *FARPROC)();

FARPROC было бы идеей Win32 "общего" указателя функции. Поэтому все, что вам нужно сделать ,это иметь аналогичный typedef (если вы не хотите использовать FARPROC Почему-то):

typedef intptr_t (*generic_funcptr_t)();    // intptr_t is typedef'ed appropriately elsewhere, 
                                            //    like in <stdint.h> or something

int GenericLoad(char* lib, generic_funcptr_t* Address, char* TheFunctionToLoad)

generic_funcptr_t Address;
GenericLoad("kernel32.dll", &Address, "UnmapViewOfFile");
LoadedUnmapViewOfFile = (MyUnmapViewOfFile) Address;

или можно обойтись без посредника и передать указатель вы действительно хотите получить значение в:

GenericLoad2("kernel32.dll", (generic_funcptr_t *) &LoadedUnmapViewOfFile, "UnmapViewOfFile");

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


адреса данных и адреса функций несовместимы. Я считаю, что ваш Address переменная должна быть указателем функции, как в вашем BOOL определение: (WINAPI *MyUnmapViewOfFile)(LPCVOID). Этот тип объявления необходим, потому что для того, чтобы иметь указатель на функцию, тип возврата, а также тип и количество аргументов должны быть известны. Это связано с тем, что при вызове функции в стеке должен быть выделен правильный объем пространства, чтобы содержать эти возвращаемое значение и параметр args.

учитывая это, я считаю, что исправление в ответе Павла является правильным (FYI, его (void**) cast-это мера безопасности типа).