Objective-C ARC和GCC({})扩展兼容性?

时间:2012-09-20 08:32:48

标签: objective-c gcc macros c-preprocessor automatic-ref-counting

我正在将一些Objective-C代码转换为ARC,大量使用GCC "Statements and Declarations in Expressions" extension ({})

GCC扩展正在预处理器宏中用于创建Objective-C对象。实际的宏相当复杂,所以这是一个简化事情的人为例子。为了我的示例的目的,假设_x参数始终为NSString *

#define f(_x) ({ NSString *x = (_x); [NSString stringWithString: x]; })

这个宏当然会被这样调用:

void foo() { NSString *s = f(@"foo"); }

在ARC之前的环境中,这很好用。 stringWithString:调用创建的对象是一个自动释放的对象,GCC扩展名将其分配给s

转换为ARC(Xcode 4.4.1)之后,当语句块退出时,对象立即被释放(我通过实例化NSLog()它的dealloc对象来确认这一点。

我尝试使用类似的类型修改宏:

#define f(_x) ({ NSString *x = (_x); (__autoreleasing id) [NSString stringWithString: x]; })

#define f(_x) ({ NSString *x = (_x); (NSString __autoreleasing *) [NSString stringWithString: x]; })

但两种形式都会导致编译错误:

Explicit ownership qualifier on cast has no effect

然后看来ARC和这个GCC扩展是不兼容的。

是这样还是我遗漏了一些简单的东西,告诉ARC不要立即释放对象?

我确实有一些选项,目前最吸引人的选择似乎是将所有这些宏转换为__inline__函数,但我有相当多的代码需要处理。我真的希望快速解决,所以任何想法都会受到赞赏。

4 个答案:

答案 0 :(得分:1)

有趣的观察,可能值得编译错误报告,因为结果明显与定义的语义相反。

您可以将作业移动到宏中:

#define f(lhs, _x) ({ NSString *x = (_x); lhs = [NSString stringWithString: x]; })

应解决发布问题。但是切换到内联函数可能更好!

答案 1 :(得分:1)

我已经调试了几个小时了,找到了解决方案,所以我会回答我自己的问题。 FWIW我同意CRD并认为这是一个错误 - 我会向Apple提交一份报告。

碰巧我为我的问题做出的“人为的例子”确实有效(doh)。正如我之前提到的那样,我正在使用的宏更加复杂,但它们却没有。我发现,如果我通过临时语句返回创建的对象作为语句块中的最后一个语句,它们。当写入时,ARC不会释放该对象。我假设clang中有一些非常窄的RVO类型代码,它与ARC解析器发生冲突。

无论如何,解决方法看起来都是这样(滚动到该行的最后):

#define f(_x) ({ NSString *x = (_x); NSString *y = [NSString stringWithString: x]; y; })

答案 2 :(得分:0)

问题是{}内的NSString * x未在{}之外定义。所以事后不能引用它,ARC释放它是正确的。你的宏不应该首先工作,因为{}块的返回值在我眼中是不确定的。

这应该可以解决问题

#define f(_x) (NSString *x = (_x); [NSString stringWithString: x]

但由于命名和多个陈述可能会产生副作用。

使用内联函数是一种更合乎逻辑的方法。

答案 3 :(得分:0)

PS:如果({})是GCC特定的宏扩展,我并不完全清楚,那么请注意Apple现在使用clang而不是GCC作为默认值。

相关问题