我正在使用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_t
types,我将FileSize()
函数的返回值赋给了一个size_tvariables,但是我得到了以下警告:
main.cpp(67):警告C4244:'初始化':从'__int64'转换为':: size_t',可能丢失数据
在这种情况下,我将如何安全地将文件的大小存储在size_t
variables中? 我知道我可以将返回值转换为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
不为零,则忽略或错误输出。