在调试模式下未检测到垃圾值

时间:2012-03-19 16:23:37

标签: objective-c ios xcode

我最近在我的代码中发现了以下内容:

for (NSInteger i; i<x; i++){
...
}

现在,显然i应该已经初始化了。我发现奇怪的是,在“调试”配置文件(XCode)中,此错误未被检测到,for循环执行没有问题。使用“发布”配置文件释放应用程序时,会发生崩溃。

哪些标志负责让这种错误在“debug”配置文件中执行?

提前致谢。

6 个答案:

答案 0 :(得分:2)

这可以被视为Heisenbug。没有初始化的声明通常会在变量的堆栈帧中分配一些空间,如果你读取变量,你将得到在内存中该位置发生的任何事情。在针对调试配置文件进行编译时,变量的存储可以与发布相比进行转换。只是在内存中用于调试模式的任何内容都不会导致崩溃(可能是正数)但在释放模式下它会导致崩溃(可能是负数)。

答案 1 :(得分:2)

clang静态分析仪应检测到这一点。我总是在建立选项时进行分析。

答案 2 :(得分:0)

我怀疑它是如此多的标志,因为编译器正在优化“未使用”变量i。发布模式包括更多优化然后调试模式。

答案 3 :(得分:0)

不同的编译器优化可能会也可能不会使用不同的内存位置或注册未初始化的变量。在开始使用变量之前,不同的垃圾(可能来自您以前使用过的变量,计算或应用程序使用的地址)将留在这些不同的位置。

“责任”不是初始化变量,因为编译器可能看不到哪些位置可能看不到垃圾,特别是在关闭最多优化的调试模式下(例如,调试版本“你很幸运”)

答案 4 :(得分:0)

在C语言中,使用初始化变量不是错误,而是未定义的行为。

存在未定义的行为,因为C被设计为非常有效的低级语言。使用初始化变量是未定义的行为,因为它允许编译器优化变量分配,因为不需要默认值。

但是,当发生未定义的行为时,编译器被许可做他想做的任何事情。 C标准常见问题解答说:

  

任何事情都可能发生;标准没有要求。程序可能无法编译,或者可能无法正确执行(崩溃或静默生成不正确的结果),或者它偶然可能完全符合程序员的意图。

因此,任何未定义行为的实现都是有效的(即使它生成的代码可以格式化您的硬盘)。

Xcode对调试和发布配置使用不同的optizations。调试配置没有优化(-O0标志),因此编译后的可执行文件必须与代码保持接近,允许您更轻松地调试它。另一方面,Release配置会生成强大优化的可执行文件(-Os标志),因为您希望应用程序快速运行。

由于存在这种差异,未定义的行为可能(或可能不会)在发布和调试配置中产生不同的结果。

虽然LLVM编译器非常详细,但默认情况下它不会针对未定义的行为发出警告。但是,您可以运行静态分析器,它可以检测到这类问题。

有关未定义行为的更多信息以及What Every Programmer Should Know About Undefined Behavior中编译器如何处理它们。

答案 5 :(得分:-1)

我还没有初始化。您只是声明i变量未初始化变量。 只写NSInteger i;只是声明一个变量而不是初始化它。 您可以通过下面提到的代码初始化变量。

for (NSInteger i=1; i<x; i++){
...
}