在Objective-C块中遇到BOOL返回类型的问题

zou*_*oul 22 objective-c objective-c-blocks

我偶然发现了BOOL块中返回类型的奇怪问题.具有以下定义:

typedef BOOL (^BoolBlock)(void);
Run Code Online (Sandbox Code Playgroud)

...此代码通过:

BoolBlock foo = ^{ return YES; };
Run Code Online (Sandbox Code Playgroud)

...但是这无法编译:

BoolBlock bar = ^{ return YES || NO; };
Run Code Online (Sandbox Code Playgroud)

出现以下错误消息:

不兼容的块指针类型使用类型为'int(^)(void)'的表达式初始化'BoolBlock'(又名'BOOL(^)(void)')

我可以使用显式转换来解决问题,但如果没有它,这不应该工作吗?有更好的解决方案吗?

Kaz*_*oto 15

|| 运算符返回int类型,如Chuck所说.

BoolBlock bar = ^{ return (BOOL)(YES || NO); };
Run Code Online (Sandbox Code Playgroud)

要么

BoolBlock bar = ^BOOL (void){ return YES || NO; };
BoolBlock bar = ^BOOL (){ return YES || NO; }; // warns in gcc, ok with clang
Run Code Online (Sandbox Code Playgroud)


Chu*_*uck 11

您可能认为||运算符在Ruby和Python等语言中工作,它在第一个操作数中返回.在C中,如果任一操作数为真,则返回1,否则返回0 - 这就是为什么它认为你返回一个整数.

  • 那么为什么像` - (BOOL)foo {返回YES || 没有; ``编译?换句话说,为什么整数和[BOOL](http://stackoverflow.com/questions/541289)之间的区别在块情况下而不是在函数1中很重要? (3认同)
  • @zoul:该函数具有显式返回类型,因此int将被隐式转换为BOOL.但是你创建的块没有显式的返回类型,所以它从return语句中推断出它的返回类型(这是一个特殊的块能力).你正在返回一个int,因此它推断该块返回一个int.只有这样,在完全推断出块的类型之后,编译器是否会根据您为其分配的变量类型检查该类型,因此会出现类型不匹配的情况. (2认同)

小智 5

正如其他人所指出的,你得到错误的原因是,e0 || e1返回int类型无关的e0e1.由于编译器根据return语句推断出块返回类型,因此您有一个返回的块,int并且您尝试将其分配给块返回类型为的块变量BOOL.

我个人更喜欢这种语法:

BoolBlock bar = ^BOOL { return YES || NO };
Run Code Online (Sandbox Code Playgroud)

为了避免错误,清楚地表明块返回类型是BOOL.rvalue是一个块文字,被理解为一个返回类型为的块,BOOL编译器应用通常的C转换.

至于为什么会发生这种情况,这是一个设计决定,尽管似乎没有明确记录.1块是一种新的语言功能.编译器设计者2已经决定它们应该在块上具有更严格的语义 - 即,块指针类型的分配必须具有严格匹配的类型 - 并且当将块分配给块变量时它们强制执行这些更严格的语义,而不管rvalue是块指针或块文字.

由于目前还没有涵盖C或C++中的块的ISO/IEC标准,编译器设计者可以自由地做出这些决定.苹果已经提交了块ISO/IEC JTC1/SC22/WG14WG14/N1370WG14/N1451,如果他们接受的话,这种行为(或者它的一些变体)应该是标准化和记录.

1 Clang的源代码确实有一条注释说明块指针的赋值比函数指针的赋值更严格.

2我亲自问过他们这件事.