warning: comparison is always true due to limited

2019-07-26 23:19发布

问题:

I have a warning that I am unable to find the cause of.

I am following instructional code in a text on Cocoa programming that implements a document based image slide show. This warning causes a while loop to be executed more than the correct number of times which causes the program to crash. The code downloaded from the author's website does not have this problem.

I assumed it was a simple matter of a typo in my version but carefully reading both versions of code I was unable to come across any differences. I then systematically replaced every .h, .m, .xib and other resource file in my version with the author's version cleaning all targets and rebuilding after each replacement.

However the warning does not go away until I finally replace the .xcodeproj file with the author's version. At which point the warning clears and the code runs without crashing. I then experimented the other way by replacing each of the .h and .m files in the author's version with my .h and .m files all at once, cleaned all targets, built and again no warnings or crashes. I thought it might be some setting in the .plist file but swapping the two versions of that file seem to have no effect. I seem to be able to narrow it down to the project.pbxproj file in the .xcodeproj bundle but I can't see how any of the build settings listed there could cause the problem.

I would appreciate it if anyone could offer any insight to the problem or can recommend a method to debug it. The warning and the related code segment with the while loop are as follows:

Build warning:

SlideShowDocument.m: In function '-[SlideShowDocument removeSlidesAtIndexes:]':
SlideShowDocument.m:191: warning: comparison is always true due to limited range of data type

Debugger console output:

Slide Master[665:a0f] HIToolbox: ignoring exception '*** -[NSCFArray objectAtIndex:]: index (4294967295) beyond bounds (3)' that raised inside

Code:

- (void)removeSlidesAtIndexes:(NSIndexSet*)indexes;
{
    NSMutableArray *slideList = [NSMutableArray array];

    unsigned int index = [indexes firstIndex];

    while (index != NSNotFound) {
        Slide *slide = [mSlides objectAtIndex:index];

        [slideList addObject:slide];

        index = [indexes indexGreaterThanIndex:index];
    }

    if ([slideList count]) {
        //remove the slides from the master list

        [self recordSlideChange];

        [mSlides removeObjectsInArray:slideList];

        [self notifySlidesChanged];
    }
}

回答1:

NSUInteger could be bigger than unsigned int, and this can depend on the build target (32bit vs 64bit, LP64 vs ILP64). From NSUInteger:

#if __LP64__ || NS_BUILD_32_LIKE_64
typedef long NSInteger;
typedef unsigned long NSUInteger;
#else
typedef int NSInteger;
typedef unsigned int NSUInteger;
#endif

If that's the case for one of your targets, NSNotFound, which is an enum value equal to NSIntegerMax (see here) won't fit in an unsigned int. So some integer promotion will come into play, and you'll never hit equality (which the compiler is telling you about) on this line:

while (index != NSNotFound) {

Declare index as an NSUInteger (the type used by by NSIndexSet for the indexes) and that problem should be solved portably.