Предположим, что есть функция библиотеки (не может изменять), которая принимает обратный вызов (указатель функции) в качестве своего аргумента, который будет вызываться в какой-то момент в будущем. Мой вопрос: есть ли способ хранения дополнительных данных вместе с указателем функции, так что при вызове обратного вызова могут быть получены дополнительные данные. Программа находится в c.Храните дополнительные данные в указателе функции c
Например:
// callback's type, no argument
typedef void (*callback_t)();
// the library function
void regist_callback(callback_t cb);
// store data with the function pointer
callback_t store_data(callback_t cb, int data);
// retrieve data within the callback
int retrieve_data();
void my_callback() {
int a;
a = retrieve_data();
// do something with a ...
}
int my_func(...) {
// some variables that i want to pass to my_callback
int a;
// ... regist_callback may be called multiple times
regist_callback(store_data(my_callback, a));
// ...
}
Проблема в том, что callback_t не принимает никаких аргументов. Моя идея состоит в том, чтобы генерировать небольшой кусок кода asm каждый раз, чтобы заполнить regist_callback, когда он вызывается, он может найти реальный обратный вызов и его данные и сохранить его в стеке (или какой-то неиспользуемый регистр), а затем перейти к реальному обратного вызова и внутри обратного вызова, данные могут быть найдены.
псевдокод:
typedef struct {
// some asm code knows the following is the real callback
char trampoline_code[X];
callback_t real_callback;
int data;
} func_ptr_t;
callback_t store_data(callback_t cb, int data) {
// ... malloc a func_ptr_t
func_ptr_t * fpt = malloc(...);
// fill the trampoline_code, different machine and
// different calling conversion are different
// ...
fpt->real_callback = cb;
fpt->data = data;
return (callback_t)fpt;
}
int retrieve_data() {
// ... some asm code to retrive data on stack (or some register)
// and return
}
Является ли это разумно? Есть ли какая-либо предыдущая работа для такой проблемы?
Почему бы не позволить 'store_date()' хранить адрес исходной функции вместе со ссылкой на 'a' в глобальной карте и получить ее с помощью' retrieve_data() '? – alk
Если вы регистрируете один и тот же обратный вызов несколько раз, когда обратный вызов вызывается, он не знает, какой из них. – jayven
Да, этот случай нельзя использовать таким образом. Однако вы можете обойти это, выполнив обертки для каждого экземпляра одновременной регистрации. Или просто используйте несколько неиспользуемых, низких (или даже высоких) битов заказа адреса cb-функции, чтобы добавить субиндекс ... - 8 байтов указателей широкие ;-) – alk