代码之家  ›  专栏  ›  技术社区  ›  Cris

为什么传递的值结构参数会损坏?

  •  1
  • Cris  · 技术社区  · 15 年前

    这不是原始代码(我在尝试简化调试时将其剥离),但它确实显示了问题所在。从表面上看,很简单:

    - (void) testMethod: (TouchData) toi  {
    
         TouchData newToi = toi;
         NSString *test = @"test string";
         NSLog(@"string: %@", test);
    
         // in ‘real’ code I pass the struct back
         // It’s void here for the simplest possible
         // case
    }
    

    TouchData是一个结构,声明如下:

    typedef struct {
        Entity *owner;
        CGPoint startPos;
        CGPoint latestPos;
        CGPoint startOfStraightSwipePos;
        NSTimeInterval startTime;
        NSTimeInterval latestTime;
        NSTimeInterval startOfStraightSwipeTime;
        CGFloat latestSpeed;
        NSMutableArray *gestures;
        BOOL isOfInterest;
    } TouchData;
    

    当我在调试器(ToI ToI)中逐步通过测试方法时 浅谈NSLO的命中 (这甚至不涉及TOI),所有的TOI成员值都突然变为零。这不会发生在拷贝(NetoTi)上。如果我通过引用传递结构,则不会发生这种情况。如果将testmethod调用直接替换为方法体(即,如果我在本地运行这些行而不是调用方法),则不会发生这种情况。如果我将to i参数类型更改为一个包含两个int成员的虚拟结构(在调用之前创建),则不会发生这种情况。

    值得指出的是,testmethod只能从自身内部调用 类,调用方刚刚从nsmutabledictionary(通过取消对nsvalue的装箱)中提取结构。但考虑到(a)结构是 通过值传递到这里的方法,以及(b)在输入它的成员时传递的值,如图所示 到了调试程序都如预期的那样,我不认为这会导致问题。结构中的两个对象指针也有棘手的问题,但是在其他上下文中,它们是OK的,它们在调试器中签入到方法中,所以我不认为我错过了基本的保留。

    我想我会遇到某种堆或堆栈损坏,但我不知道是怎么回事,也不知道为什么。I_m是Objective-C的新成员,之前曾在 垃圾收集环境,所以我的内存管理经验有限。我完全有可能错过了一些显而易见的痛苦经历。

    我希望有人会告诉我把touchdata改为对象类型,事实上我可能会这样做。我也有一些经过测试的解决方法,即要么使用副本,要么通过引用传递结构,但我真的想知道这里发生了什么。

    1 回复  |  直到 15 年前
        1
  •  2
  •   Yuji    15 年前

    如果 toi 行后不使用 TouchData newToi=toi 编译器可以在堆栈内存中执行任何它想执行的操作, 托伊 最初放在那行后面。例如,在本例中,当调用另一个函数时,它可能会重用堆栈内存。 NSLog .

    所以,看着 托伊 调试程序可能会显示出一些奇怪的东西。编译器通常会做这些事情,特别是在打开优化的情况下。即使没有优化,也无法保证 托伊 最后一次使用后保持完好。

    顺便说一下,你说里面有对象指针 托伊 没有造成问题,但这是一个棘手的情况,我强烈建议反对这种做法。遵循标准的保留/发布规则;否则,另一个查看您的代码的程序员(从现在起可能是您自己两年)将完全困惑。此外,静态分析器(可以通过在Xcode中执行构建和分析来访问)可能会混淆,并可能给出误报。所以,不要这样做。