将块传递给纯C函数所需的语法是什么?

时间:2019-07-08 16:40:49

标签: objective-c function objective-c-blocks

我有一个纯C函数,我想向其传递一个块(闭包?)。根据Apple的说法,该块应该始终是函数的最后一个参数。

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

myVoidBlockWithoutParameters(); /

return 0.0;    
}

接下来是调用C函数的Objective C代码:

- (void) testBlockFunctionality {

声明并定义块:

   void (^myBlock1)(void) ;

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

尝试不带括号直接调用该块。这行不通。 Xcode警告结果未使用。 Block的消息已记录到控制台。

    myBlock1;   

现在尝试直接调用该块,这次使用括号。这按预期工作。没有Xcode警告,并且该块的消息已记录到控制台。

    myBlock1(); 

现在调用函数,将块作为参数传递,不带括号。这可以按预期工作,但语法与先前对该块的调用不一致。

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

现在调用函数,再次将块作为参数传递,这次带括号。这不起作用,甚至无法编译,因为Xcode给出了:“将'void'传递给不兼容类型'void(^)(void)'的参数”消息。

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

最后,我实际上正在寻找定义一个传递了int参数的块,如下所示:

void(^block)(int)

但是由于我认为是语法问题,所以我无法继续进行下去。

我看过Apple的Block Programming Topics,甚至K&R C,但没有运气。

1 个答案:

答案 0 :(得分:2)

这个问题引起了一些混乱,因为块(从问题的意义上来说)不是标准C的功能。Apple在将它们添加到Objective C时将它们添加为对C和C ++编译器的扩展,但它们不是苹果生态系统之外的C事物。我承认我没有实际使用它们的经验,但是据我从文档中得知,例如these,选择的语法与C,C ++和Objective C相同。确实,一些消息来源声称语法的详细信息是专门选择的,以避免与C ++发生冲突的可能性。

从C的角度来看,接受一个块作为参数并调用以这种方式接收到的块分别完全类似于接受一个函数指针和调用所指向的函数。您的示例C函数似乎是正确的。

类似,在所有三种语言中都适用于声明和使用块-这类似于声明和使用函数指针。我相信这是故意设计的考虑因素。因此

   void (^myBlock1)(void) ;

indeed实际上将myBlock1声明为不带任何参数且不返回任何内容的块,但未定义其值。 OP观察到,在其他地方为其设置有效值(如问题中所示)

  

尝试不带括号直接调用该块。这个   不起作用。 Xcode警告结果未使用。阻止的消息是   登录到控制台。

    myBlock1;

,这确实应该是预期的。这是一个语句表达式,其计算结果是该块的值,而不是执行该块的结果。类似于

int myInt = 1;

myInt;  // specifically, analogous to this

要执行一个块,请在括号中提供一个后缀参数列表(即使该列表为空),就像通过函数指针调用函数时一样:

  

现在尝试直接调用该块,这次使用括号。   这按预期工作。没有Xcode警告,并且该块的消息是   登录到控制台。

    myBlock1();

自变量列表的存在与否可以消除是访问块的值还是对其进行调用的歧义。

困惑是关于将块传递给函数(或方法):

  

现在调用函数,将块作为参数传递,不带   括号。这可以按预期工作,但是语法不一致   与该块的上一次调用一样。

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

然而,与问题中的断言相反,该语法是完全一致的,既在内部与块语法和用法的其他方面一致,又与类似的函数指针语法和用法一致。这会将 block 传递给函数,并通过其名称标识该块。块本身被传递,而不是执行它的结果,因为没有为其提供参数列表。

  

最后,我实际上希望定义一个块   传递了一个int参数,例如:

void (^block)(int)
     

但是由于我认为是语法,所以我无法继续   问题。

接受并使用这样的块的C函数可能看起来像这样

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

给出如上所示声明的变量block,并为其值分配一个有效的块,可以像这样调用该函数:

pass_2(block);

就像我们认识到函数pass_2是由存在参数列表调用的,我们认识到变量block的值是作为参数传递的,而不是由<没有参数列表。