Объявление функции обратного вызова внутри FSEventStreamCreate

Есть пара примеров использования FSEvent для прослушивания изменений в файловой системе.

Как отслеживать изменения файловой системы MAC - kFSEventStreamCreateFlagWatchRoot

и

странность FSEvents в OS X Leopard

При создании события с FSEventStreamCreate кажется, что все они отлично передают элемент обратного вызова. Никаких параметров или чего-то еще, просто &feCallback. В основном кажется, что они передают переменную, а не функцию, если это имеет смысл.

Но я получаю ошибку Use of Undeclared identifier, когда пытаюсь это сделать. Что дает?

 FSEventStreamRef stream = FSEventStreamCreate(NULL, 
                                                  &feCallback, // what does '&' mean? Why are no parameters passed?
                                                  &cntxt, 
                                                  pathsToWatch, 
                                                  kFSEventStreamEventIdSinceNow, 
                                                  1,
                                                  kFSEventStreamCreateFlagWatchRoot );

а затем используйте функцию обратного вызова:

static void feCallback(ConstFSEventStreamRef streamRef,
                       void* pClientCallBackInfo,
                       size_t numEvents,
                       void* pEventPaths,
                       const FSEventStreamEventFlags eventFlags[],
                       const FSEventStreamEventId eventIds[]) 
{
        NSLog(@"The file changed!"); 
}

Мне бы хотелось получить пример кода, чтобы заставить работать вспомогательный объект с открытым исходным кодом: https://bitbucket.org/boredzo/fs-notifier/overview

Но то же самое. Он имеет метод:

- (id) initWithCallback:(FSEventStreamCallback)newCallback path:(NSString *)newPath;

и я не могу передать ему newCallback из-за ошибки, описанной выше.


person ck_    schedule 11.09.2011    source источник


Ответы (1)


При создании события с FSEventStreamCreate кажется, что все они отлично передают элемент обратного вызова. Никаких параметров или чего-то еще, просто &feCallback.

FSEventStreamRef stream = FSEventStreamCreate(NULL, 
                                                 &feCallback, // what does '&' mean? Why are no parameters passed?

& является оператором «адреса» и оценивается как указатель на его операнд. Здесь это не обязательно; имя функции не в вызове функции всегда оценивается как указатель на функцию, с & или без него.

Таким образом, указатель передается функции feCallback, и именно так объект FSEventStream вызовет ее обратно.

В основном кажется, что они передают переменную, а не функцию, если это имеет смысл.

Это имеет смысл, но нет, это неправильно. Они передают саму функцию.

Можно объявить переменную, содержащую указатель на функцию. Если бы feCallback была такой переменной, то feCallback и &feCallback означали бы разные вещи: feCallback был бы указателем на функцию (внутри переменной feCallback), тогда как &feCallback был бы указателем на переменную.

Однако в вашем случае, когда feCallback является функцией, эти два выражения эквивалентны; в любом случае передается указатель на функцию.

Но я получаю сообщение об ошибке использования необъявленного идентификатора, когда пытаюсь это сделать. Что дает?

Вы не объявили этот идентификатор (в данном случае эту функцию).

а затем используйте функцию обратного вызова:

Это проблема. У вас есть функция обратного вызова, определенная после того, как вы использовали ее имя, но вы не объявили функцию до использования ее имени. Вы должны объявить функцию, прежде чем сможете ее использовать (или передавать куда угодно).

Причина в том, что компилятор не знает, что такое «feCallback», пока вы не скажете ему, что и делает объявление. Когда вы пытаетесь сослаться на «feCallback» перед его объявлением или определением, компилятор не понимает, о чем вы говорите.

Другим способом было бы переместить определение функции вверх. Определение считается декларацией всего, что следует за ним. Однако я бы оставил определение там, где оно есть, и просто добавил объявление вверху файла.

В любом случае компилятор будет знать, что такое feCallback, когда вы передадите его в FSEventStreamCreate.

person Peter Hosey    schedule 11.09.2011
comment
Хм. Мне никогда не приходило в голову, что простое изменение порядка фактических функций заставит это работать. Я думал, что мне нужно как-то создать экземпляр функции, с которой у меня явно были проблемы. Если у вас есть бит static void feCallback, написанный выше, метод, в котором вы используете FSEventStreamCreate, все работает нормально. Думаю, это место, где переход от фона Java / C # (где все это делается автоматически?) Немного болезненный переход к Obj-C. :) Спасибо за помощь. - person ck_; 11.09.2011