Какой синтаксис необходим для передачи блока в чистую функцию C? - PullRequest
0 голосов
/ 08 июля 2019

У меня есть чистая функция C, которой я хотел бы передать блок (замыкание?).Согласно Apple, блок всегда должен быть последним параметром функции.

double pureCfunctionWithABlockParameter( int ignore, double ignore2, void (^myVoidBlockWithoutParameters)(void) ) {

myVoidBlockWithoutParameters(); /

return 0.0;    
}

Далее следует код Objective C для вызова функции C:

- (void) testBlockFunctionality {

объявляют и определяютblock:

   void (^myBlock1)(void) ;

    myBlock1=^(void){ NSLog(@"myBlock1 just logs this message to the console");}; 

Попытка вызвать блок напрямую, без скобок.Это не работаетXcode предупреждает результат не используется .Сообщение блока НЕ зарегистрировано на консоли.

    myBlock1;   

Теперь попытайтесь вызвать блок напрямую, на этот раз с круглыми скобками.Это работает как задумано.Нет предупреждений XCode, и сообщение блока зарегистрировано на консоли.

    myBlock1(); 

Теперь вызовите функцию, передавая блок в качестве параметра, БЕЗ скобок.Это работает как задумано, но синтаксис не согласуется с предыдущим вызовом блока.

    double someNumber;
    someNumber= pureCfunctionWithABlockParameter(0, 1, myBlock1 );     

Теперь вызовите функцию, снова передавая блок в качестве параметра, на этот раз с круглыми скобками.Это не работает, даже не скомпилируется, поскольку Xcode выдает: «Передача 'void' параметру несовместимого типа 'void (^) (void)'".

    someNumber= pureCfunctionWithABlockParameter(0, 1, myBlock1());   

В конце концов, я на самом деле ищу определенный блок, которому передается параметр int, например:

void(^block)(int)

Но я не могу перейти к этому из-за того, что ядумаю, это проблема синтаксиса.

Я смотрел в темах блочного программирования Apple и даже в K & R C, но не повезло.

1 Ответ

2 голосов
/ 08 июля 2019

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

С точки зрения C принятие блока в качестве параметра и вызов полученного таким образом блока полностью аналогичны принятию указателя на функцию и вызову функции, на которую указывает указатель, соответственно. Ваш пример функции C выглядит правильно.

Аналогичное относится к объявлению и работе с блоками на всех трех языках - это аналогично объявлению и работе с указателями на функции. Я уверен, что это было намеренное рассмотрение проекта. Таким образом

   void (^myBlock1)(void) ;

действительно объявляет myBlock1 как блок, не имеющий параметров и ничего не возвращающий, но не определяющий его значение. Установив в другом месте действительное значение, как показано в вопросе, OP наблюдает

Попытка вызвать блок напрямую, без скобок. это не работает Xcode предупреждает результат не используется . Сообщение блока: НЕ вошел в консоль.

    myBlock1;

, как и следовало ожидать. Это выражение оператора, оценивающее значение блока, а не результат выполнения блока. Это аналог

int myInt = 1;

myInt;  // specifically, analogous to this

Чтобы выполнить блок, в скобках указывается список аргументов постфикса (даже если список пуст), как при вызове функции через указатель функции:

Теперь попытайтесь вызвать блок напрямую, на этот раз в скобках. Это работает как задумано. Нет предупреждений XCode, и сообщение блока IS вошел в консоль.

    myBlock1();

Наличие или отсутствие списка аргументов - это то, что однозначно определяет, получает ли кто-то доступ к значению блока или вызывает его.

Путаница заключается в передаче блока функции (или методу):

Теперь вызываем функцию, передавая блок в качестве параметра, БЕЗ скобки. Это работает как задумано, но синтаксис не соответствует с предыдущим вызовом блока.

    double someNumber;
    someNumber= pureCfunctionWithABlockParameter(0, 1, myBlock1 );

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

В конце концов, я действительно хочу определить блок который получает параметр типа int, например:

void (^block)(int)

Но я не могу достичь этого из-за того, что я считаю синтаксисом выпуск.

Функция C, принимающая и использующая такой блок, может выглядеть следующим образом

void pass_2(void (^do_something)(int)) {
    do_something(2);
}

Учитывая переменную block, объявленную, как показано выше, и назначенную в качестве значения действительный блок, эта функция может быть вызвана так:

pass_2(block);

Точно так же, как мы узнаем, что функция pass_2 вызывается при наличии списка аргументов, мы признаем, что значение переменной block передается как аргумент - не вызывается - при отсутствии 1064 * списка аргументов.

...