19 смертных грехов, угрожающих безопасности программ. Майкл Ховард
Чтение книги онлайн.

Читать онлайн книгу 19 смертных грехов, угрожающих безопасности программ - Майкл Ховард страница 20

СКАЧАТЬ отличие от Visual Basic, Java поддерживает лишь подмножество всего диапазона целочисленных типов. Хотя 64–разрядные целые поддерживаются, но единственным беззнаковым типом является char, и он представляется в виде 16–разрядного значения без знака.

      Поскольку в Java есть только знаковые типы, проверка переполнения становится непростым делом, и по сравнению с C/C++ удается лишь избежать затруднений, связанных со смешанными операциями над знаковыми и беззнаковыми величинами.

      Греховность Perl

      По крайней мере, два автора этой книги являются горячими сторонниками Perl. Но, несмотря на это, следует признать, что работа с целыми числами реализована в Perl странно. Внутри они представляются в виде чисел с плавающей точкой двойной точности, но тестирование позволяет выявить некоторые любопытные вещи. Рассмотрим следующий код:

      $h = 4294967295;

      $i = 0xffffffff;

      $k = 0x80000000;

      print "$h = 4294967295 – $h + 1 = ".($h + 1)."\n";

      print "$i = 0xffffffff – $i + 1 = ".($i + 1)."\n";

      printf("\nИспользуется printf со спецификатором %%d\n");

      printf("\\$i = %d, \$i + 1 = %d\n\n", $i, $i + 1);

      printf("\nТестируется граничный случай деления\n");

      printf("0x80000000/-1 = %d\n", $k/-1);

      print "0x80000000/-1 = ".($k/-1)."\n";

      В результате печатается следующее:

      [e:\projects\19_sins\perl foo.pl

      4294967295 = 4294967295 – 4294967295 + 1 = 4294967296

      4294967295 = 0xffffffff – 4294967295 + 1 = 4294967296

      Используется printf со спецификатором %d

      $i = -1, $i + 1 = -1

      Тестируется граничный случай деления

      0x80000000/-1 = -2147483648

      0x80000000/-1 = -2147483648

      На первый взгляд, результат выглядит странно, особенно когда используется printf с форматной строкой (в отличие от обычной функции print). Первым делом в глаза бросается то, что мы можем присвоить переменной максимально возможное значение без знака, но после прибавления к нему 1 она либо увеличивается на единицу, либо – если печатать с помощью %d – вообще не изменяется. Загвоздка в том, что на самом деле вы оперируете числами с плавающей точкой, а спецификатор %d заставляет Perl преобразовать double в int. В действительности никакого переполнения нет, но при печати результатов создается впечатление, будто оно произошло.

      В силу особенностей работы с числами в Perl мы рекомендуем быть очень осторожными при написании на этом языке приложений, в которых много математических операций. Если вы не разбираетесь досконально в арифметике с плавающей точкой, то можете столкнуться с весьма поучительными сюрпризами. Другие языки высокого уровня, например Visual Basic, тоже иногда производят преобразования в числа с плавающей точкой. Следующий код иллюстрирует, что в таком случае происходит:

      print (5/4)."\n";

      1.25

      Для большинства обычных приложений Perl ведет себя предсказуемо и работает великолепно. Но не забывайте, что вы имеете дело не с целыми числами, а с числами с плавающей точкой, – а это «две большие разницы».

      Где искать ошибку

      Любое приложение, в котором СКАЧАТЬ