从__int64安全转换为size_t

时间:2017-10-04 12:24:35

标签: c++ c windows type-conversion warnings

我正在使用Visual Studio 2017开发Windows操作系统,并且我从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并忽略警告,但是它是否安全/正确?

4 个答案:

答案 0 :(得分:4)

这是特定于系统的。在某些系统上,size_t可能小于int64_t,这会发出警告。但是当然你不能在size_t内适应malloc。

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变量可以容纳的最大值。

答案 1 :(得分:1)

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

答案 2 :(得分:1)

在编译32位应用程序时,

size_t小于__int64

如果您知道您正在使用的文件是“小”(<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)。在这种情况下,您应该使用memory mapped files而不是较小的视图。

答案 3 :(得分:0)

如果您正在编译32位,size_t将只是32位。

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