映射LARGE_INTEGER在两个32位和64位代码的size_t
问题描述:
我试图映射文件到存储器,和calc其散列:映射LARGE_INTEGER在两个32位和64位代码的size_t
// Declaration in header file which I don't control
void SymCryptSha256(PCBYTE pbData, SIZE_T cbData, PBYTE pbResult);
// MY code
HANDLE hFile = ::CreateFile(...);
HANDLE hMap = ::CreateFileMapping(hFile, nullptr, PAGE_READONLY, 0, 0, nullptr));
byte* pMap = ::MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
BYTE[64] hash;
ULARGE_INTEGER li;
li.LowPart = ::GetFileSize(file , &li.HighPart);
// This compiles in 64-bit, but errors in 32-bit:
// error C4244: 'argument': conversion from 'ULONGLONG' to 'SIZE_T', possible loss of data
::SymCryptSha256(pMap, li.QuadPart, &hash);
这是因为SymCryptSha256
的第二个参数是SIZE_T
,在32位编译中是32位。所需的行为是:
- 64位:使用整个尺寸,这是
li.QuadPart
- 32位:在外壳尺寸> 4GB,MapViewOfFile将反正失败。所以,只需使用
li.LowPart
即可。
在我看来,我需要这样做#ifdef
s - 有没有更优雅的方式呢?
答
在一般情况下,使用this trick,你可以做这样的事情:
if (li.QuadPart > ((ULONGLONG)((size_t)(-1))) too_big();
size_t result = (size_t)(li.QuadPart);
编译器应该优化第一线成无操作在64位编译。
(你的具体情况,你可能不需要也无妨;代码将已经失败)
注:在评论已经讨论过,在这种特殊情况下最好将,如果可能的话,使用散列API,允许你散列数据块。
@harry:当然你是对的。但是,这是一个简化的例子 - 我稍后会调用其他API,它需要整个大小为'SIZE_T'。我编辑了这个问题来反映这一点。 – Jonathan
@Jonathan:哈利是对的,我检查了我的旧代码,我也是这样做的,如果你想要*任何*文件的计算哈希值,就通过0 ... – Malkocoglu
- 你需要准备好文件可以大于4GB。所以你不需要将它映射到内存中(当然,这对于相对较小的文件来说更简单快捷),而对块来说则是部分块。选择块大小 - 然后映射块,计算哈希,取消映射,然后映射下一个块。大块大小必须足够大多数文件使用单个块,但对于非常大的文件,您将有多个映射/取消映射 – RbMm