从__int64到size_t的安全转换

我正在使用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()dynamic地分配内存。 由于函数malloc()接受size_ttypes,我将FileSize()函数的返回值赋给了一个size_tvariables,但是我得到了以下警告:

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

在这种情况下,我将如何安全地将文件的大小存储在size_tvariables中? 我知道我可以将返回值转换为size_t并解除警告,但它是安全的还是正确的?

这是非常系统特定的。 在某些系统上, size_t可能小于int64_t ,这会给出警告。 但是,无论如何,malloc不能超过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变量可容纳的最大值的常量。

在编译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 ... } 

另一方面,如果文件可能很大,那么你不能假设你将能够一次读入整个内存,因为机器可能没有足够的内存,或者你的地址空间可能会用完(通常大约2GB一个32位Windows进程)。 在这种情况下,您应该使用内存映射文件,而不是使用较小的视图。

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

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

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