安全转换从__int64到size_t

Safe conversion from __int64 to size_t

本文关键字:size int64 安全 转换      更新时间:2023-10-16

我正在使用Visual Studio 2017在Windows OS上工作,我获得了以下功能,以确定一个SO答案之一的文件大小:

__int64 FileSize(const char *filename)
{
    HANDLE hFile = CreateFile(filename, GENERIC_READ,
        FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE) {
        return -1; // error condition, could call GetLastError to find out more
    }
    LARGE_INTEGER size;
    if (!GetFileSizeEx(hFile, &size)) {
        CloseHandle(hFile);
        return -1; // error condition, could call GetLastError to find out more
    }
    CloseHandle(hFile);
    return size.QuadPart;
}

因此,正在使用它来确定文件大小,以便将内存相应地用malloc()分配。由于函数malloc()接受size_t类型,因此我将FileSize()函数的返回值分配给size_t变量,但是我收到了以下警告:

main.cpp(67):警告c4244:'初始化':从'__int64'到':: size_t'的转换,可能会丢失数据

在这种情况下,我如何安全地将文件大小存储在size_t变量中?我知道我可以将回报值投入到size_t并删除警告,但这会安全/正确吗?

这是非常特定于系统的。在某些系统上,size_t可能小于int64_t,这会发出警告。但是,当然,无论如何,您都不能超越size_t内的东西。

最有可能安全执行size_t s = (size_t)some_int64;

但是,如果您感到偏执,可以添加检查/断言:

#include <stdint.h>
...
if(some_int64 > SIZE_MAX) // this line is fully portable
{
  halt_and_catch_fire();
}

SIZE_MAX是一个常数,代表size_t变量可容纳的最大值。

size_t类型已实现定义。因此,无法确保可以将__int64的值安全存储在size_t类型中。我建议使用static_assert:

static_assert(sizeof(__int64)<=sizeof(size_t), 
"Unable to safely store an __int64 value in a size_t variable");

如果size_t小于__int64,这将在编译过程中造成错误。

请参阅http://en.cppreference.com/w/cpp/types/size_t有关更多信息。

size_t在编译32位应用程序时小于__int64

如果您知道正在使用的文件是"小"(&lt; 2 gb),则可以通过铸造来稍微回避问题,如果文件很大,则可以中止:

UINT64 size = FileSize(...);
if (size > ~(size_t)0) // You might want to use SIZE_MAX instead of the ~ trick if you want to stay portable
{
  printf("File is too large!n");
}
else
{
  void*data = malloc((size_t) size);
  if (!data)
    printf("Out of memory, file is too large?n");
  else
    ...
}

另一方面,如果文件可能很大,那么您不能假设您将能够立即将整个内容读入内存,因为机器可能没有足够的内存,或者您可能会耗尽地址空间在32位Windows过程中2 GB)。在这种情况下,您应该使用较小视图的内存映射文件。

如果您要编译32位,则size_t仅为32位。

因此,建议您返回size.LowPart,如果size.HighPart不是零,则忽略或错误。