6

我已使用此 c++ 代码在 Windows 中查找某些文件的文件大小(使用 Visual Studio):

(p_findFileData->nFileSizeHigh * MAXDWORD) + p_findFileData->nFileSizeLow);

如果文件大于 4gb,这并没有给我正确的文件大小。经过一些研究,我尝试了:

(p_findFileData->nFileSizeHigh * (MAXDWORD+1)) + p_findFileData->nFileSizeLow); 

当我读到 nfilesizehigh 和 nfilesizelow 是文件大小的 64 位值中的每个 32 位时,如果文件大小值大于 32 位,我们将 maxdword(在我的情况下为 0xffffffff)乘以 nfilesizehigh。第二种解决方案也不起作用,并且给了我比原来更小的尺寸。我再次尝试了这个:

ULONGLONG FileSize = (FindFileData.nFileSizeHigh * 4294967296) + FindFileData.nFileSizeLow;

它奏效了。此外,我还使用了另一种解决方案来获取文件大小:

 ULONGLONG FileSize = FindFileData.nFileSizeHigh;
 FileSize <<= sizeof( FindFileData.nFileSizeHigh ) *8; 
 FileSize |= FindFileData.nFileSizeLow;

上述解决方案也有效:

我想知道为什么前两个解决方案不起作用,如果可能的话,我还想知道最后一个解决方案的解释,因为我想知道代码的内部工作。帮助将不胜感激。

4

4 回答 4

10

使用ULARGE_INTEGER结构来组合值,而不是尝试手动计算/移动它们:

ULARGE_INTEGER ul;
ul.HighPart = p_findFileData->nFileSizeHigh;
ul.LowPart = p_findFileData->nFileSizeLow;
ULONGLONG FileSize = ul.QuadPart;
于 2013-03-04T20:41:00.690 回答
8

我会使用:

ULONGLONG FileSize = (static_cast<ULONGLONG>(FindFileData.nFileSizeHigh) <<
                      sizeof(FindFileData.nFileSizeLow) *8) |
                     FindFileData.nFileSizeLow;

在 32 位值进入 FileSize 变量之前,必须转换为 ULONGLONG 才能将 32 位值转换为 64 位值。

您当然也可以使用乘法 - 但它在任何特定方式上都不是“更好”,而且很可能会慢一点[在这种特殊情况下可能没什么大不了的,但我可以看到使用乘法没有任何好处.

现在对于“不工作”的变体:

即使这确实有效:

 (p_findFileData->nFileSizeHigh * MAXDWORD) + p_findFileData->nFileSizeLow);

你会得到错误的值,因为MAXDWORD它小于 4GB,所以你最终会得到错误的值 [是的,它可能很接近,但它至少会错 1 个字节,可能更多]。但是,由于我们处理的是 32 位值,它实际上变成了:

 -p_findFileData->nFileSizeHigh + p_findFileData->nFileSizeLow;

因为MAXDWORD与 -1 相同(是的,它很可能是一个无符号值,但如果你以这种方式使值溢出,它的行为与负符号值相同)。

这个在数学上是正确的,但由于它溢出了一个 32 位值,所以它不起作用。

 (p_findFileData->nFileSizeHigh * (MAXDWORD+1)) + p_findFileData->nFileSizeLow);

所以你得到了low part + (0 * high part)当然是不正确的。

使用演员表,这将起作用:

 static_cast<ULONGLONG>(p_findFileData->nFileSizeHigh) * (MAXDWORD+1) +
 p_findFileData->nFileSizeLow;
于 2013-03-04T19:23:23.723 回答
3
(p_findFileData->nFileSizeHigh * MAXDWORD) + p_findFileData->nFileSizeLow);

这不会给出正确的结果,因为 MAXDWORD 是错误的值。

(p_findFileData->nFileSizeHigh * (MAXDWORD+1)) + p_findFileData->nFileSizeLow); 

这不起作用,因为您在将类型转换为足以容纳该值的大小之前向 MAXDWORD 添加了 +1。

(FindFileData.nFileSizeHigh * 4294967296) + FindFileData.nFileSizeLow;

这是有效的,因为4294967296它是 64 位类型。

FileSize <<= sizeof( FindFileData.nFileSizeHigh ) *8; 
FileSize |= FindFileData.nFileSizeLow;

这是有效的,因为您将高位移动 32(这与乘以 4294967296 相同),然后使用按位或“添加”低位。

于 2013-03-04T19:21:14.847 回答
1

我遇到了完全相同的问题,对于我的代码来说答案非常简单。只需将 MAXDWORD 转换为 64 位 int(例如 uint64_t)。这背后的解释可以在我收到的答案中找到

于 2018-11-06T09:27:43.197 回答