' void(*)(int)'与' void(^)(int)'?

时间:2016-03-23 13:18:16

标签: c++ objective-c

今天,我正在进行从C ++到Objective-c方法的回调传递 最后,我解决了这个问题,但是一些代码让我感到困惑 在Objective-c中,人们普通使用block来实现一个回调,一个块声明如下:

  

returnType(^ blockName)(parameterTypes)

我还学习了C ++回调,这是一个相同类型的回调定义如下:

  

returnType(* funcName)(parameterTypes)

当我将回调从C ++传递给Objective-c时,编译器警告我:

"Cannot initialize a parameter of type 'void (^)(int)' with an rvalue of type 'void (*)(int)"

最后,我将^更改为*,它有效。我想知道,^*在定义中的区别是,它们具有相同的行为吗?

3 个答案:

答案 0 :(得分:2)

这是一个块:

returnType (^blockName)(parameterTypes)

这是一个函数指针:

returnType (*funcName)(parameterTypes)

它们不兼容。

答案 1 :(得分:1)

标准C和C ++没有可调用块。然而,显然,这些语言的一些编译器确实将该功能作为扩展来实现。我看到的一些文档表明它也是Objective C的Apple扩展,但由于Objective C在Apple世界之外很少使用,这可能是一个没有区别的区别。

无论使用何种语言,如果将回调实现为函数,则必须通过函数指针将该回调呈现给预期的调用者,并且调用者必须准备好以该形式接受它。另一方面,如果您将回调实现为块,则必须通过块指针将其呈现给调用者,并且调用者必须准备好接受 形式。这两者不可互换,并且它们具有不同的语法,您已经介绍过了。有可能设计一种机制,可以通过单独的参数或完全独立的注册功能接受这两种形式。

答案 2 :(得分:1)

Objective-C块(^)与函数指针(*)不兼容。
与函数指针相比​​,它们具有从周围上下文中捕获值和变量的好处(它们是闭包)。

编写一个从块调用函数指针的包装器很容易:

typedef int (*funptr)(int);
typedef int (^funblock)(int);


int use_block_callback(int y, funblock fb)
{
    return fb(y);
}

int use_funptr_callback(int y, funptr f)
{
     return use_block_callback(y, ^ int (int x) { return f(x); }); 
}

int add_one(int x) { return x + 1; }

int foo(int x)
{
    return use_funptr_callback(23, add_one);
}

// Or
int (*some_pointer)(int) = add_one;
int (^some_block)(int) = ^ int (int x) { return some_pointer(x); } 

enter image description here