Вызывать имя функции, а не указатель функции
На странице man для libffi есть пример, который, по сути, требует указателя на функцию (в этом примере, puts
).
Однако, что мне делать, если я знаю только имя функции, но на самом деле у меня нет указателя (что обычно происходит, если ffi используется, скажем, в динамических языках программирования)?
Скажем, я хочу сделать что-то вроде этого (псевдокод):
cif = null
s = "Hello World"
args = []
values = []
args[0] = ffi.type_pointer
values[0] = address_of(s)
if(ffi.prepare(cif, ffi.DEFAULT_ABI, ffi.type_uint, args)):
ffi.call(cif, "puts", values)
Короче говоря, я хочу, чтобы libffi динамически просматривал функцию (если она поддерживается ffi, в первую очередь), похожую на dlfcn/LoadLibrary, а затем вызывал ее с помощью предоставленных типов FFI CIF.
Возможно ли такое с libffi? Как будет выглядеть простой пример?
1 ответ
Есть две возможности - одна, требующая обдумывания со стороны программиста.
В зависимости от o / s, существуют средства, связанные с общими библиотеками для поиска символов из программы или ее общих библиотек.
Во многих системах Unix и, в частности, в Linux средства объявлены в <dlfcn.h>
и являются dlopen()
а также dlsym()
(а также dlclose()
, так далее). При наличии соответствующего дескриптора для разделяемой библиотеки, вы можете использовать:
int (*ffi_ptr)(const char *) = dlsym(ffi_handle, "ffi_function_name");
Вы должны рассмотреть кастинг - обычно жестокий - чтобы избежать предупреждений компиляции.
Альтернативный, заранее продуманный метод заключается в создании таблицы имен функций и указателей функций, в которой вы можете искать имя и использовать соответствующий указатель:
struct ptr_function
{
void (*func_ptr)(void);
const char *func_name;
};
static const struct ptr_function[] =
{
{ func_1, "func_1" },
{ func_2, "func_2" },
{ func_2, "func_synonym" },
};
enum { NUM_PTR_FUNCTION = sizeof(ptr_function) / sizeof(*ptr_function) } ;
Обратите внимание, что этот метод учитывает синонимы таким образом, что dlsym()
Механизм нет. Тем не менее, премедикация часто является основным камнем преткновения. Это метод, который восходит к 80-м и началу 90-х годов, когда общие библиотеки не были доступны повсеместно. Еще раз, необходимость в приведениях может сделать код несколько более сложным.