Delphi 警告 W1073 组合有符号类型和无符号 64 位类型 - 被视为无符号类型

Delphi Warning W1073 Combining signed type and unsigned 64-bit type - treated as an unsigned type

我在以下代码行收到主题警告;

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

具体来说,IDE 突出显示第三行。

SelectedFilesSize 声明为 UInt64。

当我 运行 时代码似乎可以工作;如果我 select 一个项目,它的文件大小被添加到总数中,如果我 deselect 一个文件,它的大小被减去。

我知道我可以通过{$WARN COMBINING_SIGNED_UNSIGNED64 OFF}来抑制这个警告。

谁能解释一下?如果 SelectedFilesSize 变大,是否会产生不可预见的影响?或者对特定目标平台的影响?

Delphi 10.3,Win32 和 Win64 目标

这将在这里工作,但警告是正确的。

如果将 UInt64-1 相乘,实际上是将其与 $FFFFFFFFFFFFFFFF 相乘。最终结果将是一个 128 位的值,但低 64 位将与带符号的乘法相同(这也是代码生成器经常生成 imul 的原因)操作码,即使是未签名的乘法:低位将是正确的,只是 - unused - 高位不会)。高 64 位无论如何都不会被使用,所以它们无关紧要。

如果您将该值(实际上是负值)添加到另一个 UInt64(例如 SelectedFilesSize),则 64 位 结果 将再次正确。 CPU 在添加时不区分正值或负值。结果 CPU flags (进位,溢出)将指示溢出,但如果您通过不使用范围或溢出检查来忽略它,您的代码将没问题。

不过,如果范围检查或溢出检查打开,您的代码可能会产生运行时错误。

换句话说,这是可行的,因为可以忽略任何多余的高位(第 64 位及以上)。否则,值将是错误的。参见示例。

例子

假设你的IdList.GetPropertyValue(TShellColumns.Size)是420。那么你的表现是:

[=10=]000000000001A4 * $FFFFFFFFFFFFFFFF = [=10=]000000000001A3FFFFFFFFFFFFFF5C

这是一个巨大的但是正数,幸好低64位($FFFFFFFFFFFFFF5C)可以解释为-420(一个真正的负值在 128 位中将是 $FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5C-420).

现在假设你的 SelectedFileSize100000(或十六进制 [=22=]000000000186A0)。然后你得到:

[=11=]000000000186A0 + $FFFFFFFFFFFFFF5C = [=11=]000000000184FC 
(or actually 0000000000184FC, but the top bit -- the carry -- is ignored).

[=23=]000000000184FC 是十进制的 99580,所以正是您想要的值。