arrayscobjective-cfor-loopcompiler-optimization

Weird compiler optimization/behavior regarding a "for" loop without a body in Objective-C


I have the following C array of NSString *:

static NSString *const OrderByValueNames[] = {@"None",@"Added",@"Views",@"Rating",@"ABC",@"Meta"};

Now, I want to check the length of this array at runtime so I wrote the following method:

NSInteger LengthOfArray(NSString *const array[])
{
    NSInteger length = 0;
    // For Loop Without a body!
    for (length = 0; array[length] != nil; length++);
    return length;
}

Now, when I run this code at debug configuration, everything is fine and the function returns the right result.

BUT as soon as I switch to release configuration and run it again, the program freezes at the for loop. After 10 seconds of the loop being executed, iOS kills the app for not responding. Weird.

Now, if I add body to the loop, like that:

for (length = 0; array[length] != nil; length++)
{
    NSLog(@"%d",length);
}

Then it's working fine even in release mode.

Giving the loop an empty body, like that:

for (length = 0; array[length] != nil; length++){}

Still freezes in release mode.

My guess is that there is a compiler optimization when running in release mode, but what exactly?!

Any ideas?


Solution

  • C-style arrays are not nil-terminated by default. If you want to check the length this way, you need to add the terminator yourself.

    static NSString *const OrderByValueNames[] =
       {@"None",@"Added",@"Views",@"Rating",@"ABC",@"Meta",nil};
    

    A much better way to find the length is simply this:

    length = sizeof(OrderByValueNames) / sizeof(OrderByValueNames[0]);
    

    (Note that this trick doesn't work if you pass the array into a function, since it then degenerates into a pointer.)