Подтвердить что ты не робот

Зачем мне нужно проверять больше, чем Int32.MaxValue?

Я использую Visual Studio 2010 SP1 Ultimate в проекте библиотеки классов С# (.net 4), и мне интересно что-то...

Учитывая этот метод:

public void DoSomethingBrilliant(int input)
{
    if (input == int.MaxValue)
        throw new ArgumentOutOfRangeException("input");

    input++;

    Console.WriteLine(input);
}

Я получаю это предупреждение от анализа кода:

CA2233: Microsoft.Usage: исправьте потенциальное переполнение в операции "ввод + 1" в "Test.DoSomethingBrilliant(int)".

Я подумал про себя: это немного странно, так как я проверяю, что операция input++ не будет переполняться, выбросив это простое исключение в начале, но я изменил его на это:

public void DoSomethingBrilliant(int input)
{
    if (input >= int.MaxValue)
        throw new ArgumentOutOfRangeException("input");

    input++;

    Console.WriteLine(input);
}

и, конечно же, предупреждение ушло.

Теперь мой маленький мозг запутался, потому что, учитывая, что я получаю int в качестве аргумента, почему бы проверить, больше ли он чем максимальное значение, допустимое для целого числа, когда-либо предоставляющее какую-либо ценность?

Затем я вернулся к исходному биту кода и переключился на отладку, и он был построен без предупреждения! Любопытный и любопытный...

Я проверил различия между debug и release и обнаружил, что если я поставлю галочку в опции "Оптимизировать код", предупреждение из анализа кода появится справа.

Таким образом, оптимизация приводит к чему-то, что означает, что мне нужно проверить больше int.MaxValue. А? Зачем? Неужели я очень плотный? Что сделала оптимизация, это означает, что я мог бы получить int больше int.MaxValue, переданный в метод, принимающий int?

Или это просто ошибка в функции анализа кода?

Обновление

Вот IL для "неоптимизированной" версии (где анализ кода получает это право):

.method public hidebysig instance void  DoSomethingBrilliant(int32 input) cil managed
{
  // Code size       40 (0x28)
  .maxstack  2
  .locals init ([0] bool CS$4$0000)
  IL_0000:  nop
  IL_0001:  ldarg.1
  IL_0002:  ldc.i4     0x7fffffff
  IL_0007:  ceq
  IL_0009:  ldc.i4.0
  IL_000a:  ceq
  IL_000c:  stloc.0
  IL_000d:  ldloc.0
  IL_000e:  brtrue.s   IL_001b
  IL_0010:  ldstr      "input"
  IL_0015:  newobj     instance void [mscorlib]System.ArgumentOutOfRangeException::.ctor(string)
  IL_001a:  throw
  IL_001b:  ldarg.1
  IL_001c:  ldc.i4.1
  IL_001d:  add
  IL_001e:  starg.s    input
  IL_0020:  ldarg.1
  IL_0021:  call       void [mscorlib]System.Console::WriteLine(int32)
  IL_0026:  nop
  IL_0027:  ret
} // end of method Test::DoSomethingBrilliant

и здесь это для оптимизированной версии (где она ошибается):

.method public hidebysig instance void  DoSomethingBrilliant(int32 input) cil managed
{
  // Code size       31 (0x1f)
  .maxstack  8
  IL_0000:  ldarg.1
  IL_0001:  ldc.i4     0x7fffffff
  IL_0006:  bne.un.s   IL_0013
  IL_0008:  ldstr      "input"
  IL_000d:  newobj     instance void [mscorlib]System.ArgumentOutOfRangeException::.ctor(string)
  IL_0012:  throw
  IL_0013:  ldarg.1
  IL_0014:  ldc.i4.1
  IL_0015:  add
  IL_0016:  starg.s    input
  IL_0018:  ldarg.1
  IL_0019:  call       void [mscorlib]System.Console::WriteLine(int32)
  IL_001e:  ret
} // end of method Test::DoSomethingBrilliant

Я вижу кучу дополнительных вызовов до операции броска, но я буду честен - я понятия не имею, что они делают!

4b9b3361

Ответ 1

Или это просто ошибка в функции анализа кода?

Похоже на это. Не удивительно, если честно - сделать такой анализ кода идеальным, это сложно. Учитывая, что какой-либо конкретный int не может быть больше int.MaxValue, >= и ==, безусловно, эквивалентны.

Ответ 2

Смотрите эти фрагменты кода:

if (x == int.MaxValue) return;
// x != int.MaxValue

и

if (x >= int.MaxValue) return;
// x < int.MaxValue

и

// x < int.MaxValue
// rewrite
// x + 1 <= int.MaxValue
x++;
// x <= int.MaxValue

Постусловие x ++ показывает (по деривации), что предварительное условие должно быть:

x < int.MaxValue 

который может быть установлен только в том случае, если вы проверяете:

x >= int.MaxValue