我在以下代码行中收到主题警告;
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目标
答案 0 :(得分:3)
这将在这里起作用,但警告是正确的。
如果将 UInt64 乘以-1
,则实际上是将其乘以$FFFFFFFFFFFFFFFF
。最终结果将是一个128位的值,但低64位将与有符号乘法相同(这也是代码生成器经常生成imul
操作码的原因,甚至对于无符号乘法:低位将是正确的,只是-未使用-高位将是不正确的)。高64位将不会被使用,所以没关系。
如果将该值(实际上为负)添加到另一个 UInt64 中(例如 SelectedFilesSize ),则64位的结果将再次正确。加法时,CPU不会区分正值或负值。产生的CPU 标志(进位,溢出)将指示溢出,但是如果您不使用范围或溢出检查而忽略了它,那么您的代码就可以了。
但是,如果启用了范围检查或溢出检查,您的代码可能会产生运行时错误。
换句话说,之所以可行,是因为任何多余的高位(第64位及以上)都可以忽略。否则,值将是错误的。参见示例。
示例
假设您的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
,因此正是您想要的值。