Delphi Warning W1073 Объединение 64-разрядного типа со знаком и без знака - рассматривается как тип без знака - PullRequest
0 голосов
/ 16 января 2019

Я получаю предупреждение о предмете в следующей строке кода;

SelectedFilesSize := SelectedFilesSize +
  UInt64(IdList.GetPropertyValue(TShellColumns.Size)) *
  ifthen(Selected, 1, -1);

В частности, в среде IDE выделяется третья строка.

SelectedFilesSize объявлен как UInt64.

Код, кажется, работает, когда я его запускаю; если я выбираю элемент, его размер файла добавляется к общему количеству, если я отменяю выбор файла, его размер вычитается.

Я знаю, что могу отключить это предупреждение с {$ WARN COMBINING_SIGNED_UNSIGNED64 OFF}.

Может кто-нибудь объяснить? Будет ли непредвиденное влияние, если SelectedFilesSize станет огромным? Или влияние на конкретную целевую платформу?

Delphi 10.3, Win32 и Win64 цели

1 Ответ

0 голосов
/ 16 января 2019

Это будет работать здесь, но предупреждение верно.

Если вы умножаете UInt64 на -1, вы фактически умножаете его на $FFFFFFFFFFFFFFFF. Конечным результатом будет 128-битное значение, , но младшие 64 бита будут такими же, как и для умножения со знаком (именно поэтому генератор кода часто выдает код операции imul, даже для умножения с несимметричным умножением. : младшие биты будут правильными, только & mdash; unused & mdash; старшие биты не будут). Старшие 64 бита все равно не будут использоваться, поэтому они не имеют значения.

Если вы добавите это (фактически отрицательное) значение к другому UInt64 (например, SelectedFilesSize ), 64-битный результат снова будет правильным. Процессор не различает положительные или отрицательные значения при добавлении. Результирующие CPU flags (перенос, переполнение) будут указывать на переполнение, но если вы проигнорируете это, не используя проверки диапазона или переполнения, ваш код будет в порядке.

Ваш код, скорее всего, выдаст ошибку времени выполнения, если включены проверки диапазона или переполнения.

Другими словами, это работает, потому что любой лишний старший бит & mdash; 64-й бит и выше - & mdash; можно игнорировать . В противном случае значения будут неправильными. Смотрите пример.

Пример * +1031 ** * одна тысяча тридцать две Скажите, что IdList.GetPropertyValue(TShellColumns.Size) составляет 420. Затем вы выполняете:

$00000000000001A4 * $FFFFFFFFFFFFFFFF = $00000000000001A3FFFFFFFFFFFFFF5C

Это огромное , но положительное число, но, к счастью, младшие 64 бита ($FFFFFFFFFFFFFF5C) можно интерпретировать как -420 (действительно отрицательное значение в 128 битах будет $FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5C или -420).

Теперь скажите, что ваш SelectedFileSize равен 100000 (или гекс $00000000000186A0). Тогда вы получите:

$00000000000186A0 + $FFFFFFFFFFFFFF5C = $00000000000184FC 
(or actually $100000000000184FC, but the top bit -- the carry -- is ignored).

$00000000000184FC - это 99580 в десятичном виде, поэтому именно то значение, которое вы хотели.

...