文件大小计算,Int64,以及32位和64位之间的差异

时间:2011-02-10 15:28:36

标签: delphi delphi-2010

我遇到以下代码问题:

var
  FileSize : Int64;
...
FileSize := Info.nFileSizeLow or (Info.nFileSizeHigh shl 32);

我预计它会因为作业左侧的Int64类型而起作用。但事实并非如此。包含shl的部分计算似乎会产生溢出。

所以我把它改成了:

FileSize := Info.nFileSizeLow or (Int64 (Info.nFileSizeHigh) shl 32);

适用于我的32位操作系统,但不适用于Vista 64位!

最后,

FileSize := Info.nFileSizeHigh;
FileSize := FileSize shl 32;
FileSize := Info.nFileSizeLow or FileSize;

适用于两个系统。

有人可以解释这三个版本的差异吗?

5 个答案:

答案 0 :(得分:5)

一般来说,表达式a * b的类型,其中ab的类型为Integer,*是一个适用于Integer的运算符,是一个整数类型与Integer相同。 (我通常说,作为例外/。)为了使运算符使用64位运算,一个或多个操作数必须具有只能用64位类型表示的范围。这应该导致所有操作数被提升为64位,并执行64位操作。

赋值的左侧是64位的这一事实通常对赋值运算符右侧的表达式的解释和输入没有影响。这就是我所知道的几乎所有语言都有静态调度的32位和64位运算符重载的方式(与任意精度整数或数字塔上的多态调度运算符相反);使事情表现不佳将是非常令人惊讶的行为。

例如,过程调用的参数实际上是对参数的隐式赋值。如果赋值的左侧可以更改右侧表达式的解释,我们将不知道如何在不知道定义的情况下将参数解释为过程调用:

var a, b: Integer;
// ...
P((a shl 16) or b); // 32-bit operation or 64-bit operation?

我不知道您为什么会看到第二版和第三版代码的不同行为。据我所知,它们应该被解释为相同,在我的测试中,它们的解释是相同的。如果您可以提供适用于32位Windows但在64位Windows上失败的示例代码,我可以进一步调查。

答案 1 :(得分:2)

实际上,这在Delphi 7的帮助文件中有很好的文档,在“整数类型”下:

  

通常,对整数的算术运算返回Integer类型的值 - 在其当前实现中,它等效于32位Longint。仅当在一个或多个Int64操作数上执行时,操作才返回Int64类型的值。因此,以下代码会产生错误的结果。

提供的代码示例:

var
  I: Integer;
  J: Int64;
  ...
I := High(Integer);
J := I + 1;
  

要在这种情况下获取Int64返回值,请将I转换为Int64:

 ...
J := Int64(I) + 1;

答案 2 :(得分:1)

首先,FileSize必须定义为UInt64而不是Int64 ...

UInt64(在早期的Delphi版本中不可用)是一个无符号的64位整数,也就是QWORD。这是FileSize的预期类型(您不会期望文件大小为负,不是吗?)。

恕我直言,您可以使用UInt64进行编码,因为我们不希望将某些值报告为否定值:

FileSize := UInt64(Info.nFileSizeLow) or (UInt64(Info.nFileSizeHigh) shl 32));

但在Delphi 7下,它会生成与您相​​同的完整代码。

FileSize := Info.nFileSizeLow or (Int64(Info.nFileSizeHigh) shl 32));

所以可能有一些编译器回归。你能看一下asm生成的代码(步调试器然后是Alt + F2),看看是否有区别。但这不太可能......

在所有情况下,这是一个更好(更快)的代码:

with Int64Rec(FileSize) do
begin
  Lo := Info.nFileSizeLow;
  Hi := Info.nFileSizeHigh;
end;

关于WIN32_FIND_DATA结构的official MSDN documentation个状态:

  

nFileSizeHigh:文件大小的高位DWORD值,以字节为单位。

     

除非文件大小大于MAXDWORD,否则此值为零。

     

文件的大小等于   (nFileSizeHigh *(MAXDWORD + 1))+   nFileSizeLow。

     

nFileSizeLow:文件大小的低位DWORD值,以字节为单位。

以下是生成的代码:

FileSize := UInt64(Info.nFileSizeLow)+(UInt64(Info.nFileSizeHigh)*UInt64(1 shl 32));

确实很有趣的定义......

答案 3 :(得分:0)

这不是一个真正的答案,但是评论的时间太长了。

我注意到当将表达式的结果写入64位变量时,Delphi会感到困惑,但操作数是32位。当我实现一个返回64位数字的哈希函数时,我遇到了这个错误。你的第三种变体是有效的,因为你是第一次分配64位变量,帮助Delphi发现它确实需要进行64位运算。

我很想说变体(1)和(2)实际上都是失败的,因为Delphi生成32位算术,然后将结果赋予64位变量。我很想说在你的32位机器上运行良好的变体可以从某种“不幸的非故障”中获益(即:代码很糟糕,但是它对于给定的测试产生了良好的结果)。问题是,当从32位机器移动到64位机器时,COMPILED代码不会改变。如果代码相同,输入是相同的,你必须将错误固定在CPU上,但是你知道你没有在CPU中发现错误,所以你必须退回并重新考虑你的测试,或将其固定在“unluck non-failure”上。

答案 4 :(得分:0)

对Delphi 7和版本2进行测试是可以的。必须是更高版本的错误