среда, 4 марта 2009 г.

Почему операции с Byte дают в результате Integer?

Это перевод Why do operations on "byte" result in "int"? Автор: Реймонд Чен.

Люди жалуются, что следующий код выдаёт ошибку:
const
  B = Byte(1);
  C: Byte = not B; // Constant expression violates subrange bounds (*)
Они говорят: "Результат операции с 'Byte' должен быть ещё одним 'Byte', а не 'Integer'".

Будьте осторожны в своих желаниях. Они могут вам не понравиться.

Предположим, мы бы жили в вымышленном мире, где операции с 'Byte' приводят к результату в виде 'Byte'.
const
  B: Byte = 32;
  C: Byte = 240;
var
  I: Integer;
begin
  I := B + C; // Чему равно I?
В этом вымышленном мире, значение I было бы 16! Почему? Потому что оба операнда в операторе + являются Byte, поэтому сумма "B + C" также будет Byte, что приводит к результату 16 из-за переполнения (и, как я уже заметил ранее, целочисленные переполнения являются новым вектором атак).

Аналогично,
  I := -B;
приведёт к тому, что I будет равно 224 а не -32, по той же причине.

Вы действительно хотите этого?

Рассмотрим следующий более тонкий сценарий:
type
  TResults = record
    Wins: Byte;
    Games: Byte;
  end;

function WinningAverage(const Captain, CoCaptain: TResults): Bool;
begin
  Result :=  (Captain.Wins + CoCaptain.Wins) >= 
            ((Captain.Games + CoCaptain.Games) div 2);
end;
В нашем воображаемом мире этот код возвращал бы неверные значения, если суммарное число сыгранных матчей превысило бы 255. Для исправления вам пришлось бы вставлять эти надоедливые приведения типов:
function WinningAverage(const Captain, CoCaptain: TResults): Bool;
begin
  Result :=  (Integer(Captain.Wins) + CoCaptain.Wins) >= 
            ((Integer(Captain.Games) + CoCaptain.Games) div 2);
end;
Получается: что бы вы ни сделали - всё равно в каком-то случае вам придётся вставлять преобразования типов. И уж лучше иметь ошибку языка на стороне безопасности (когда компилятор принуждает вас вставлять явное преобразование в те места, где вы уверены, что там нет проблем с переполнением), чем на стороне тихого скрытия проблемы (когда вы можете не заметить пропущенные преобразования, пока ваш отдел бухгалтерии не спросит вас, а чего это у них в конце месяца цифры не сходятся).

Примечание переводчика:
(*) На самом деле, более правильным объявлением было бы B: Byte = 1;, но проблема в том, что компилятор не считает такое объявление за константу (да, даже при выключенной опции Assignable typed constants), поэтому во втором объявлении будет ошибка "Constant expression expected".

Комментариев нет:

Отправить комментарий

Можно использовать некоторые HTML-теги, например:

<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>

Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку (поддерживается OpenID).

Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.

Ваше сообщение может быть помечено как спам спам-фильтром - не волнуйтесь, оно появится после проверки администратором.