我最近在查看一些代码,在
GetLastError()
失败后确实调用了 HeapAlloc()
。但是,根据 HeapAlloc 函数 MSDN 文档:
如果函数失败,它不会调用SetLastError。应用程序无法调用 GetLastError 来获取扩展错误信息。
互联网上充斥着在
GetLastError()
失败后调用 HeapAlloc()
的代码片段,我认为大多数程序员(包括我自己)都被编程为在 API 失败时自然地调用 GetLastError()
。
为了测试,我创建了这个示例来分配最大内存量:
#include <windows.h>
#include <stdio.h>
#include <stdint.h>
int main() {
HANDLE hHeap = GetProcessHeap();
if (hHeap == NULL) {
printf("Failed to get the process heap.\n");
return 1;
}
SetLastError(0); // Clear the last error
// Attempt to allocate a very large amount of memory
SIZE_T largeSize = SIZE_MAX;
LPVOID pMemory = HeapAlloc(hHeap, 0, largeSize);
if (pMemory == NULL) {
DWORD dwError = GetLastError();
printf("HeapAlloc failed: ");
switch (dwError) {
case ERROR_NOT_ENOUGH_MEMORY:
printf("Not enough memory available.\n");
break;
case ERROR_OUTOFMEMORY:
printf("Insufficient memory to satisfy the request.\n");
break;
default:
printf("Error code: %lu\n", dwError);
}
}
else {
printf("Memory allocation successful.\n");
HeapFree(hHeap, 0, pMemory);
}
return 0;
}
输出显示:
HeapAlloc 失败:没有足够的可用内存。
问题
为什么
GetLastError()
看起来有效?难道这只是运气,所以大家应该避免调用它,因为依靠GetLastError()
获取详细的错误信息可能不可靠?
更新
HeapAlloc()
的官方文档注释:
如果函数失败,它不会调用SetLastError。应用程序无法调用 GetLastError 来获取扩展错误信息。
但是,从下面的评论来看,
HeapAlloc()
的内部实现可能会与TEB中的LastErrorValue
交互,但没有为外部开发人员提供文档,并且依赖于操作系统。
这是
HeapAlloc
在 TEB 中使用 LastErrorValue
8 (0x8) 更新 ERROR_NOT_ENOUGH_MEMORY
的快照。
总而言之,我会坚持使用官方文档而不是调用
GetLastError()
。谢谢。
为了测试,[...]
您无法“测试”合同是否有效。
合同是。
前置条件和后置条件的组合称为契约。 实施有权放宽其先决条件并加强其后置条件。当这种情况发生时,它被称为“实施细节”。 实施细节不属于合同的一部分。
如果
的文档指出应用程序无法调用
GetLastError
来获取扩展错误信息。
那么这就是与其后置条件相关的契约。当
GetLastError
返回
HeapAlloc
时,不要调用 NULL
。