недоразумение заключается в том, что clang / checker не может гарантировать, что массивы count
не изменятся, и не может быть уверена, что программа будет работать так, как будто ваши массивы неизменны.
MyНа самом деле вопрос в том, насколько важны эти предупреждения, и если моя программа работает должным образом, без ошибок (ну, без ошибок, связанных с этими предупреждениями: D), могу ли я их безопасно игнорировать?Я просто чувствую, что не стоит игнорировать Xcode;это довольно умно.
Лично я не игнорирую их и действительно стараюсь не допустить этих проблем.
Вы можете немного изменить свою программу, чтобы привести ее в соответствие с потоком программ.ожидает компилятор / проверка.Самый простой способ сделать это и удалить большинство предупреждений - это ввести переменную, которую, как вы ожидаете, изменить нельзя:
NSArray* overlayLat = [arrayOne objectAtIndex:1];
const NSUInteger overlayLatCount = [overlayLat count];
// now use the variable instead of calling the method where needed:
double lats[overlayLatCount];
...
Затем используйте эти переменные вместо методов.Естественно, вы должны быть осторожны, чтобы убедиться, что создаваемые вами переменные всегда будут равны значению, которое они представляют.
Есть еще несколько битов: средство проверки не всегда знает семантику типа.Например: вы могли бы подумать, что подсчет NSArray может быть кэширован, но контролер должен знать много о многих классах, чтобы понять эти проблемы.Более того, программа проверки не может гарантировать, что программа будет работать так, как вы ожидаете, по многим другим причинам.Допустим, счетчик массива был кэширован как оптимизация;это приведет к куче ошибок в реальных программах.Таким образом, вы должны сделать некоторые вещи немного более очевидными, когда у вас есть контекст, на который может не рассчитывать контролер - вам необходимо ввести этот контекст в некоторых случаях.
первый набор проблем, более подробно
NSArray * overlayLat = [arrayOne objectAtIndex:1];
const NSUInteger overlayLatCount = [overlayLat count];
double lats[overlayLatCount];
NSArray * overlayLong = [arrayOne objectAtIndex:2];
const NSUInteger overlayLongCount = [overlayLong count];
double longs[overlayLongCount];
NSArray * annotationLat = [arrayOne objectAtIndex:8];
const NSUInteger annotationLatCount = [annotationLat count];
double annotationLats[annotationLatCount];
NSArray * annotationLong = [arrayOne objectAtIndex:9];
const NSUInteger annotationLongCount = [annotationLong count];
double annotationsLongs[annotationLongCount];
for (int iii = 0; iii < overlayLatCount; iii++) {
NSNumber * a = (NSNumber*)[overlayLat objectAtIndex:iii];
lats[iii] = [a doubleValue];
}
for (int iii = 0; iii < overlayLongCount; iii++) {
NSNumber * a = (NSNumber*)[overlayLong objectAtIndex:iii];
longs[iii] = [a doubleValue];
}
for (int iii = 0; iii < annotationLongCount; iii++) {
NSNumber * a = (NSNumber*)[annotationLong objectAtIndex:iii];
annotationsLongs[iii] = [a doubleValue];
}
for (int iii = 0; iii < annotationLatCount; iii++) {
NSNumber * a = (NSNumber*)[annotationLat objectAtIndex:iii];
annotationLats[iii] = [a doubleValue];
}
Сведения об оставшихся проблемах
1) Объявленный VLA имеет нулевой размер:
Значение: средство проверки видит, что sizeLats
инициализируется нулем и увеличивается только условно.Он предупреждает вас, что длина массива может быть равна нулю.
Разрешение: прежде чем продолжить, проверьте на ноль:
if (0 == sizeLats) return;
CLLocationCoordinate2D coords[sizeLats];
Это один из способов гарантировать компилятору, что вы не будете создавать или использоватьнулевая длина VLA.
2) Левый операнд! = является значением мусора:
if ((lats[iii] != 0) && (longs[iii] != 0)) {
Значение: средство проверки не может гарантировать, что массив когда-либо был полностью инициализирован и что sizeLats
меньше [overlayLat count]
и [overlayLong count]
.Что еще более важно, он должен предупреждать о возможности доступа вне зоны доступа.Это сообщение не очень четкое.
Разрешение: На самом деле в программе есть немного неконтролируемых границ и предположений (и, возможно, некоторая проверка ошибок была удалена).Это должно быть прояснено для проверки и компилятора.Вы должны сделать это более понятным для компилятора и добавить некоторое обнаружение ошибок на всякий случай (предоставит более полный пример).
Дополнительные примечания - сравнения с плавающей запятой не очень безопасны - вы не должны ожидать, что массивы C будутinitialized
3) Аргумент вызова функции является неинициализированным значением.
Значение: Источник этой проблемы совпадает с # 2 «Левый операнд! = является значением мусора».Массив по указанному индексу, возможно, не был инициализирован.Еще хуже проблема заключается в том, что нет гарантии, что индекс массива будет в диапазоне.Тот факт, что он не помечен как таковой, заставляет задуматься, не отключил ли это предупреждение это предупреждение из-за слишком большого количества ложных срабатываний.
Разрешение: То же, что # 2
Итак, более подробный пример срасширенная проверка ошибок может flow , как в следующей программе.Программа не очень красива и может использовать некоторую очистку / рефакторинг, но вся проверка ошибок существует, она проходит без проблем с проверкой, делает сомнительный код недоступным и обнаруживает большое количество ошибок.Я все еще не считаю сравнения с плавающей запятой или VLA хорошими, но этого должно быть достаточно, чтобы решить ваш вопрос.
/**
@brief fills a double buffer with values from an NSArray
@param destinationBuffer the buffer to fill
@param countOfDestinationBuffer the number of elements in @a destinationBuffer
@param the source values. an NSArray filled with NSNumber objects. @a countOfDestinationBuffer must be equal to @a [source count]
@return false if an error occurred, else true
*/
static bool FillDoubleArrayFromNSArray(double* const destinationBuffer, const NSUInteger countOfDestinationBuffer, NSArray* source) {
const NSUInteger sourceCount = [source count];
if ((0 == destinationBuffer) || (0 == countOfDestinationBuffer) || (0 == [source count])) {
assert(0 && "invalid argument");
return false;
}
else if (sourceCount != countOfDestinationBuffer) {
assert(0 && "buffer size mismatch");
return false;
}
for (NSUInteger idx = 0; idx < sourceCount; ++idx) {
NSNumber* a = (NSNumber*)[source objectAtIndex:idx];
destinationBuffer[idx] = [a doubleValue];
}
return true;
}
- (void)addLines {
NSArray* arrayOne = [NSArray array];
NSArray* overlayLatArray = [arrayOne objectAtIndex:1];
const NSUInteger overlayLatCount = [overlayLatArray count];
if (0 == overlayLatCount) {
assert(0 && "empty array or invalid object. bailing.");
return;
}
double lats[overlayLatCount];
if (!FillDoubleArrayFromNSArray(lats, overlayLatCount, overlayLatArray)) {
/* do something */
return;
}
NSArray* overlayLongArray = [arrayOne objectAtIndex:2];
const NSUInteger overlayLongCount = [overlayLongArray count];
if (0 == overlayLongCount) {
assert(0 && "empty array or invalid object. bailing.");
return;
}
double longs[overlayLongCount];
if (!FillDoubleArrayFromNSArray(longs, overlayLongCount, overlayLongArray)) {
/* do something */
return;
}
NSUInteger sizeLat = 0;
for (NSUInteger idx = 0; idx < overlayLatCount; ++idx) {
if (lats[idx] != 0) {
++sizeLat;
}
}
if (0 == sizeLat) {
assert(0 && "what to do when no lines can be drawn?");
return;
}
if ((overlayLatCount < sizeLat) || (overlayLongCount < sizeLat)) {
assert(0 && "input range error (overlayLongCount is really what we are testing here)");
return;
}
CLLocationCoordinate2D coords[sizeLat];
for (NSUInteger idx = 0; idx < sizeLat; ++idx) {
if ((lats[idx] != 0) && (longs[idx] != 0)) {
coords[idx] = CLLocationCoordinate2DMake(lats[idx], longs[idx]);
}
else if (0 == idx) {
assert(0 && "range error. access of invalid index would have occurred");
return;
}
else {
coords[idx] = coords[idx - 1];
}
}
NSArray* annotationLatArray = [arrayOne objectAtIndex:8];
const NSUInteger annotationLatCount = [annotationLatArray count];
if (0 == annotationLatCount) {
assert(0 && "empty array or invalid object. bailing.");
return;
}
double annotationLat[annotationLatCount];
if (!FillDoubleArrayFromNSArray(annotationLat, annotationLatCount, annotationLatArray)) {
/* do something */
return;
}
NSArray* annotationLongArray = [arrayOne objectAtIndex:9];
const NSUInteger annotationLongCount = [annotationLongArray count];
if (0 == annotationLongCount) {
assert(0 && "empty array or invalid object. bailing.");
return;
}
double annotationLong[annotationLongCount];
if (!FillDoubleArrayFromNSArray(annotationLong, annotationLongCount, annotationLongArray)) {
/* do something */
return;
}
if (annotationLatCount < annotationLongCount) {
assert(0 && "input range error in next loop. bailing");
return;
}
for (NSUInteger idx = 0; idx < annotationLongCount; ++idx) {
CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(annotationLat[idx], annotationLong[idx]);
/* ... */
}
}