为什么它是“exc_bad_access”而不是“运行时”或“编​​译时”错误?

时间:2014-07-04 09:16:12

标签: ios objective-c xcode memory exc-bad-access

ScreenShot : running mode of xCode 5.1

为什么它是exc_bad_access而不是run-timecompile-time错误?

我错误地写了"@age"而不是@"age",这引起了我的好奇心。

我对exc_bad_access的理解是Bad-Access是由指针(好的引用)dereferenced引起的内存位置引起的尚未分配或取消分配或未经授权访问(const或某事)。

但在这种情况下,我只是将数据写入内存,语法与NS Objective-c格式不匹配。因此,它应该是运行时错误而不是 Bad-Access

我在哪里错过了这个概念?

4 个答案:

答案 0 :(得分:24)

获得EXC_BAD_ACCESS的原因是-initWithObjects:方法期望其所有参数都是有效的Objective-C对象。每个Objective-C对象都以一个小标题开头;这曾经是一个简单的指针,称为isa,它的类对象(它不一定非常简单,现在你不应该嘲笑自己;有Objective-C运行时API你可以在必要时使用。)

这里没有遇到编译器错误的原因是C / C ++ / Objective-C中没有办法为“varargs”方法或函数指定正确的类型。因此,编译器允许您传递任何类型的参数,假设您知道自己在做什么。

无论如何,在-initWithObjects:的实现中,它将尝试向您传入的每个对象发送-retain消息。当它这样做时,它将尝试取消引用{ {1}}指针。对于C字符串,这意味着它将把字符串的前四个或八个字节视为指针。这不太可能有一个好的结果,很可能你马上得到EXC_BAD_ACCESS。即使你很幸运,他们碰巧指向有效的内存,Objective-C运行时也会指望它们指向一个有效的isa结构,这种结构非常不太可能,并且结果也很可能是一个EXC_BAD_ACCESS。

答案 1 :(得分:3)

事实上,"@age"const char*,因此它似乎与您对exc_bad_access的描述相符。

答案 2 :(得分:2)

如上所述@"age"是创建NSString *的快捷方式 - 它同样是NSObject的子类。字符串前面的@告诉编译器创建并返回NSString *

另一方面,

"@age"没有@前缀,因此编译器会创建一个const char *,这是C用来表示字符串的内容。请记住,Objective-C是C的严格超集,这意味着任何C代码都将在Objective-C编译器上编译。这也意味着编译器需要保持C的向后兼容性 - 这意味着"@age"是C字符串,而@"age"是Objective-C Foundation Kit NSString对象。

关于你的问题:这不是编译器错误的原因是因为NSArray的initWithObjects:初始化程序没有指定所需的类型。它简单地说了一个指针列表。并且因为@"age"NSString *)都是指针而"@age"const char *)也是指针,编译器不会抱怨。两者都是编译器允许定义initWithObjects:的方式。

现在你说为什么它不是运行时错误。 EXC_BAD_ACCESS是运行时错误。您可能意味着为什么没有抛出异常,因为异常和运行时错误存在差异。但是,异常也是运行时错误,但可以检测并执行它们。通常无法对信号(EXC_BAD_ACCESS)执行操作,并且应用程序将被操作系统终止。

它是运行时错误的原因是因为initWithObject:期望列出NSObjects,并且此函数所做的第一件事就是对提供的对象进行一些检查或处理。现在,在Objective-C运行时内部,它基本上是一个C struct,其中包含有关对象方法和变量的信息。这些结构通常包含一个指向对象超类的指针。你给这个方法的基本上是垃圾。当它试图检查它认为是带有指针和数据的结构时 - 它得到的只是一个四字节缓冲区("age\0")。因此,当它尝试作为一个示例取消引用时,该方法所认为的超类指针是一个结构,它将在该四字节缓冲区之外读取,因此您的应用程序将收到EXC_BAD_ACCESS

所以你有它。从编译器的角度来看,你没有做错任何事。从运行时的角度来看,你正在为它提供垃圾,它无法检测到它。它只是处理数据,就像它预期的那样。当它这样做时,它超出了你提供的缓冲区的边界,因此得到EXC_BAD_ACCESS

希望这能澄清你的好奇心。

答案 3 :(得分:1)

语法@"name"是字符串文字,与使[[NSString alloc] initWithUTF8String:"name\0"];成为对象的"@age"相同

另一方面,

const char*NSArrayconst char*只能处理对象,因此给它NSLog();会导致您的应用崩溃。我不确定为什么静态分析器首先没有发现这个问题,我很惊讶,至少没有警告告诉你使用文字,例如{{1}}