Как получить предупреждение при сравнении двух значений enum - PullRequest
0 голосов
/ 02 июля 2018

В этом небольшом ДЕМО в Objective-C:

первое перечисление:

typedef NS_ENUM(NSUInteger, Day) {
     DaySunday,
     DayMonday,
     DayTuesday
};

второе перечисление:

typedef NS_ENUM(NSUInteger, Month) {
    MonthJanuary,
    MonthFebruary,
    MonthMarch,
    MonthApril
};

при сравнении:

Day sunday = DaySunday;
Month january = MonthJanuary;
if (sunday == january) {
     NSLog(@"case1 with warning");
  }
if (DaySunday == january) {
     NSLog(@"case2 without warning");
  }

и снимок Xcode: enter image description here

так как я могу получить предупреждение в случае2?

Ответы [ 3 ]

0 голосов
/ 02 июля 2018

Я не уверен, почему такое поведение происходит, но это странно и круто. Чтобы получить предупреждение, вы должны привести DaySunday к типу Day явно.

if ((Day)DaySunday == january) {
    NSLog(@"case2 without warning");
}

Явное приведение january к Month не вызовет предупреждение, поэтому похоже, что статический анализатор правильно обрабатывает january как тип Month (потому что вы объявили его таким образом), но неявно преобразование DaySunday, чтобы сравнение работало.

Чтобы быть справедливым, предупреждение в первом случае на самом деле не является идеальным поведением, потому что и Day, и Month являются NSUIntegers и, следовательно, сравнимы. Как вы заметили, когда вы запускаете этот код, оба сравнения верны, что означает, что предупреждение на самом деле не имеет смысла.

0 голосов
/ 02 июля 2018

Типы перечисления в (Objective-) C являются очень слабыми типами. Согласно стандарту C каждая константа перечисления (ваш january и т. Д.) Имеет целочисленный тип, не тип перечисления. Кроме того, значение типа перечисления неявно преобразуется в целочисленный тип при необходимости.

Clang выдает предупреждение, когда оба операнда имеют тип перечисления, и это всего лишь предупреждение , так как по стандарту C сравнение является правильным, когда между целочисленными значениями.

В вашем DaySunday == january левый операнд имеет целочисленный тип, правый операнд неявно преобразуется в целочисленный тип, поэтому, опять же, это вполне допустимый и правильный стандарт C. Clang может выбрать для выдачи предупреждения, Вероятно, причина этого заключается не в конструктивном решении или следствии замысла внутри Clang.

Будьте благодарны, Clang часто дает предупреждения, когда Стандарт C не требует их, однако вы не можете полагаться на него, показывая все ловушки в C.

Чтобы решить вашу проблему, вы можете привести литерал к типу enum, если хотите, (Day)DaySunday == january, но вы можете разумно решить, что это делает C еще хуже; -)

0 голосов
/ 02 июля 2018

Вы должны изменить enum на int для удаления Warning

 if ((int)sunday == (int)january) {
    NSLog(@"case1 with warning");
}
...