Возможно ли реализовать замыкания в C? (Генерация обратных вызовов без глобальных ссылок) - PullRequest
0 голосов
/ 24 апреля 2020

Предположим, у меня есть алгоритм, который принимает обратный вызов:

void algorithm(void (*callback)()){
   (*callback)(a,b,c);
}

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

A лучше, более общий интерфейс может быть:

void algorithm(void (*callback)(), void* cbdata, <...some parameter...>){
   (*callback)(cbdata, a,b,c);
}

... теперь я могу реализовать все виды поведения, и мне не нужно определять новую функцию для каждого. Например, cbdata может быть указателем на структуру данных экземпляра + метода C ++, и обратный вызов вызывает этот метод вместе с экземпляром. Этот экземпляр C ++ теперь может обеспечить все виды поведения для обратного вызова.

Однако, к сожалению, у нас может быть интерфейс, который нам дан, а не тот, который мы хотим.

void algorithm(void (*callback)(), <...some parameter...>){
   (*callback)(a,b,c);
}

. .. у нас нет слота для предоставления cbdata нашему обратному вызову.

На других языках просто сократить вызов функции с параметрами до одного с меньшим количеством параметров с замыканиями. Как это можно сделать в C? Интерфейс принимает один обратный вызов, но я не хочу реализовывать библиотечную функцию для каждого поведения - я бы хотел, скажем, определить одну функцию, которая может реализовывать много поведений.

Я нашел Достижение закрытия в C, но оно страдает от проблем, связанных с тем, что «параметр закрытия» хранится в стеке:

int main(void) {
  struct ClosureData* cbdata;
   ...

  int callback(int a, int b, int c) {
    ...
    cbdata->method(cbdata->self);
    ...  
  };

  algorithm(&callback);
}

Это может быть неудобно, если мы хотим установить обратные вызовы в инициализация библиотеки и возврат из функции инициализации.

Поскольку C обратные вызовы являются указателем на (C соглашение о вызове) код, который должен быть выполнен, я думаю, что нам понадобится новый указатель на новый код. Итак ... возможно ли, что в работающей программе я могу «создать» новую программную память, в которую я могу поместить ссылку на свои данные, а затем получить указатель на функцию?

Это кажется трудным, но не невозможным. Загрузка разделяемой библиотеки / DLL подразумевает добавление новых ссылочных участков кода во время работы программы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...