Кастинг пустого указателя (данные) к указателю функции

Управление исходным кодом ничего не стоит Вам кроме времени установки его. Это - просто легкая задача.

6
задан Assaf Lavie 9 December 2009 в 03:23
поделиться

3 ответа

Правильный код - это одна строка:

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

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

3
ответ дан 16 December 2019 в 21:41
поделиться

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

Учитывая это, я считаю, что исправление в ответе Павла правильное (к сведению, его (void **) приведение типов является мерой безопасности типов).

2
ответ дан 16 December 2019 в 21:41
поделиться

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

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

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

Если вы хотите, чтобы что-то соответствовало стандартам, вам нужно использовать «общий» указатель на функцию вместо указателя void - C гарантирует, что указатель функции может быть преобразован в любой другой указатель на функцию и обратно без потерь, так что это будет работать независимо от вашей платформы. Вероятно, поэтому возвращаемое значение Win32 GetProcAddress () API возвращает FARPROC , который является просто определением типа для указателя функции на функцию, которая не принимает никаких параметров (или, по крайней мере, неуказанных параметров) и возвращает 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 . Подобно ошибке №1 здесь: http://blogs.msdn.com/sdl/archive/2009/07/28/atl-ms09-035-and-the-sdl.aspx

Теперь вы должны быть установлен. Однако, как бы вы ни смотрели на это, вам нужно будет выполнить опасное заклинание. Даже в C ++ с шаблонами вам придется выполнять приведение на каком-то уровне (хотя вы можете скрыть его в функции шаблона), потому что API GetProcAddress () не знает фактический тип указатель на функцию, который вы извлекаете.

Также обратите внимание, что ваш интерфейс для GenericLoad () имеет, возможно, серьезную проблему проектирования - он не дает возможности управлять временем жизни библиотеки. Это может не быть проблемой, если вы намерены не разрешить выгрузку библиотеки, но пользователи могут захотеть этого, поэтому вам следует рассмотреть эту проблему.

com / sdl / archive / 2009/07/28 / atl-ms09-035-and-the-sdl.aspx

Теперь все готово. Однако, как бы вы ни смотрели на это, вам нужно выполнить опасное заклинание. Даже в C ++ с шаблонами вам придется выполнять приведение на каком-то уровне (хотя вы можете скрыть его в функции шаблона), потому что API GetProcAddress () не знает фактический тип указатель на функцию, который вы извлекаете.

Также обратите внимание, что ваш интерфейс для GenericLoad () имеет, возможно, серьезную проблему проектирования - он не дает возможности управлять временем жизни библиотеки. Это может не быть проблемой, если вы намерены не разрешить выгрузку библиотеки, но пользователи могут захотеть этого, поэтому вам следует рассмотреть эту проблему.

com / sdl / archive / 2009/07/28 / atl-ms09-035-and-the-sdl.aspx

Теперь все готово. Однако, как бы вы ни смотрели на это, вам нужно будет выполнить опасное заклинание. Даже в C ++ с шаблонами вам придется выполнять приведение на каком-то уровне (хотя вы можете скрыть его в функции шаблона), потому что API GetProcAddress () не знает фактический тип указатель на функцию, который вы извлекаете.

Также обратите внимание, что ваш интерфейс для GenericLoad () имеет, возможно, серьезную проблему проектирования - он не дает возможности управлять временем жизни библиотеки. Это может не быть проблемой, если вы намерены не разрешить выгрузку библиотеки, но пользователи могут захотеть этого, поэтому вам следует рассмотреть эту проблему.

как бы вы ни смотрели на это, вам нужно будет выполнить опасное заклинание. Даже в C ++ с шаблонами вам придется выполнять приведение на каком-то уровне (хотя вы можете скрыть его в функции шаблона), потому что API GetProcAddress () не знает фактический тип указатель функции, который вы извлекаете.

Также обратите внимание, что ваш интерфейс для GenericLoad () имеет, возможно, серьезную конструктивную проблему - он не дает возможности управлять временем жизни библиотеки. Это может не быть проблемой, если вы намерены не разрешить выгрузку библиотеки, но пользователи могут захотеть этого, поэтому вам следует рассмотреть эту проблему.

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

Также обратите внимание, что ваш интерфейс для GenericLoad () имеет, возможно, серьезную проблему проектирования - он не дает возможности управлять временем жизни библиотеки. Это может не быть проблемой, если вы намерены не разрешить выгрузку библиотеки, но пользователи могут захотеть этого, поэтому вам следует рассмотреть эту проблему.

d необходимо выполнить приведение на каком-то уровне (хотя вы можете скрыть его в функции шаблона), потому что API GetProcAddress () не знает фактического типа указателя функции, который вы получаете .

Также обратите внимание, что ваш интерфейс для GenericLoad () имеет, возможно, серьезную конструктивную проблему - он не дает возможности управлять временем жизни библиотеки. Это может не быть проблемой, если вы намерены не разрешить выгрузку библиотеки, но пользователи могут захотеть этого, поэтому вам следует рассмотреть эту проблему.

d необходимо выполнить приведение на каком-то уровне (хотя вы можете скрыть его в функции шаблона), потому что API GetProcAddress () не знает фактического типа указателя функции, который вы получаете .

Также обратите внимание, что ваш интерфейс для GenericLoad () имеет, возможно, серьезную конструктивную проблему - он не дает возможности управлять временем жизни библиотеки. Это может не быть проблемой, если вы намерены не разрешить выгрузку библиотеки, но пользователи могут захотеть этого, поэтому вам следует рассмотреть эту проблему.

Также обратите внимание, что ваш интерфейс для GenericLoad () имеет, возможно, серьезную конструктивную проблему - он не дает возможности управлять временем жизни библиотеки. Это может не быть проблемой, если вы намерены не разрешить выгрузку библиотеки, но пользователи могут захотеть этого, поэтому вам следует рассмотреть эту проблему.

Также обратите внимание, что ваш интерфейс для GenericLoad () имеет, возможно, серьезную конструктивную проблему - он не дает возможности управлять временем жизни библиотеки. Это может не быть проблемой, если вы намерены не разрешить выгрузку библиотеки, но пользователи могут захотеть этого, поэтому вам следует рассмотреть эту проблему.

3
ответ дан 16 December 2019 в 21:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: