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
).
现在假设你的 SelectedFileSize
是 100000
(或十六进制 [=22=]000000000186A0
)。然后你得到:
[=11=]000000000186A0 + $FFFFFFFFFFFFFF5C = [=11=]000000000184FC
(or actually 0000000000184FC, but the top bit -- the carry -- is ignored).
[=23=]000000000184FC
是十进制的 99580
,所以正是您想要的值。
我在以下代码行收到主题警告;
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
).
现在假设你的 SelectedFileSize
是 100000
(或十六进制 [=22=]000000000186A0
)。然后你得到:
[=11=]000000000186A0 + $FFFFFFFFFFFFFF5C = [=11=]000000000184FC
(or actually 0000000000184FC, but the top bit -- the carry -- is ignored).
[=23=]000000000184FC
是十进制的 99580
,所以正是您想要的值。