Приведение указателя 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-это мера безопасности типа).