- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我从 C++ 代码调用 Windows API,我有一个辅助方法来执行 FormatMessage
内容并抛出异常以进行错误处理。函数的签名是
void throw_system_error(const std::string& msg_prefix, DWORD messageid)
我注意到了一些奇怪的事情。此代码无法正常工作:
handle = ...;
if (handle == NULL) {
throw_system_error("something bad happened", GetLastError());
}
传递给 throw_system_error
的错误代码始终为零。
因为这工作得很好:
handle = ...;
if (handle == NULL) {
DWORD error = GetLastError();
throw_system_error("something bad happened", error);
}
更多的调查表明这个版本有同样的问题:
handle = ...;
if (handle == NULL) {
std::string msg("something bad happened");
DWORD error = GetLastError();
throw_system_error(msg, error);
}
它寻找整个世界,就好像 std::string
的构造函数正在重置错误代码。
我的猜测是 std::string
正在内部分配内存,这会导致一些系统调用,然后将最后一个错误设置回零。
有人知道这里到底发生了什么吗?
Visual C++ 2015,64 位。
最佳答案
让我们看看 GetLastError文档:
Most functions that set the thread's last-error code set it when they fail. However, some functions also set the last-error code when they succeed.
You should call the GetLastError function immediately when a function's return value indicates that such a call will return useful data. That is because some functions call SetLastError with a zero when they succeed, wiping out the error code set by the most recently failed function.
所以有一个调用 SetLastError 的函数,很可能是一个分配内存的函数:当你构造一个字符串时,new
被调用来分配内存。
现在,让我们看看new
在vc++中的实现。 Stack Overflow 中对这个问题有一个很好的答案:https://softwareengineering.stackexchange.com/a/293209
It depends if you are in debug or release mode. In release mode, there is HeapAlloc/HeapFree which are kernel functions,
while in debug mode (with visual studio) there is a hand written version of free and malloc (to which new/delete are re-directed) with thread locks and more exceptions detection, so that you can detect more easily when you did some mistakes with you heap pointers when running your code in debug mode.
所以在 Release模式下,调用的函数是HeapAlloc ,它不调用 SetLastError。来自文档:
If the function fails, it does not call SetLastError
所以代码应该在 Release模式下正常工作。然而,在调试实现中,函数 FlsGetValue 被调用,并且该函数在成功时调用 SetLastError。
检查这个很容易,
#include <iostream>
#include <Windows.h>
int main() {
DWORD t = FlsAlloc(nullptr);
SetLastError(23); //Set error to 23
DWORD error1 = GetLastError(); //store error
FlsGetValue(t); //If success, it is going to set error to 0
DWORD error2 = GetLastError(); //store second error code
std::cout << error1 << std::endl;
std::cout << error2 << std::endl;
system("PAUSE");
return 0;
}
输出如下:
23
0
所以 FlsGetValue 调用了 SetLastError()。为了证明它仅在调试时被调用,我们可以进行以下测试:
#include <iostream>
#include <Windows.h>
int main() {
DWORD t = FlsAlloc(nullptr);
SetLastError(23); //Set error to 23
DWORD error1 = GetLastError(); //store error
int* test = new int; //allocate int
DWORD error2 = GetLastError(); //store second error code
std::cout << error1 << std::endl; //output errors
std::cout << error2 << std::endl;
delete test; //free allocated memory
system("PAUSE");
return 0;
}
如果你在 Debug模式下运行它,它会给你,因为它调用了 FlsGetValue:
23
0
但是,如果你在 Release模式下运行它,它会产生,因为它调用了 HeapAlloc:
23
23
关于c++ - 为什么 std::string 构造函数重置 GetLastError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39168416/
处理 Application_Error 中的错误时,我应该使用这两个中的哪一个? 我正在为两者找到多个示例,但不清楚一个是否比另一个更好。是否存在只有一个会显示正确错误的情况? 另外,我怀疑这很重要
不久前,我为 Windows API 函数编写了一个简单的包装器类。我编写了一组单元测试来验证该类生成的结果与直接调用 API 相匹配。 最近我回去添加了关于跨不同线程使用包装器类的单元测试。我发现
这个问题不太可能帮助任何 future 的访问者;它只与一个小的地理区域、一个特定的时间点或一个非常狭窄的情况有关,这些情况并不普遍适用于互联网的全局受众。为了帮助使这个问题更广泛地适用,visit
我有一个函数,它为每种情况返回不同的 DWORD 值,如果出现错误。所以我有以下定义: #define ERR_NO_DB_CONNECTION 0x90000 #define ERR_DB_N
德尔福 Xe。 在delphi帮助中:“...调用此函数通常会重置操作系统错误状态...” 如何将当前错误重置为 0? IE。 GetLastError=0 示例: Try // There is a
在调用像 ExtractShortPathName 这样的 Windows API 函数包装器后使用 GetLastError 时,我注意到 GetLastError 返回一个非零错误代码,无论是否对
我正在尝试编写一些函数来创建仅用于使用剪贴板的 Windows 消息窗口。我知道创建窗口失败,但是当我添加 GetLastError() 函数调用时,该函数永远不会返回到 Java。这使得调试变得很棘
这非常类似于: Turning GetLastError() into an exception 我还希望能够将 std::string 添加到错误中: class Win32Exception
下面是一个创建线程的简单程序。我希望我遗漏了一些明显的东西。仅供引用 - 我是 Win32 的新手。 为什么线程执行中的GetLastError()返回87(ERROR_INVALID_PARAMET
我有一个函数可以将 GetLastError 函数转换为字符串以在我的项目中使用。但在部署之前,我需要在示例程序中进行测试。当我测试它时,它没有给我任何错误,因为示例程序没有任何错误。 谁能帮我如何在
在此示例中,dwerror 是 10045L。但此代码返回 0x13d 值作为错误。如何获取格式消息?请看一下。 TCHAR lpMsgBuf[512]; if(!FormatMessage(
我有一个可以打开很多窗口的应用程序。有时,我得到 wglCreateContext() 返回 0 而 GetLastError() 返回 0xc007001f。 它只发生在 Intel 显卡上。 有人
我知道 GetLastError 会在发生错误时立即调用。我写了函数: void PrintErrorMsg() { DWORD errCode = GetLastError(); L
为什么 QT 应用程序中的最后一个错误始终为零? SetLastError(23); qDebug() << "LastError: " << GetLastError(); 预期输出:最后一个错误:
假设我正在使用 APC,其中过程和调用代码都使用 SetLastError 和 GetLastError。这会导致 GetLastError 产生不可预测的值。有什么办法可以解决这个问题吗? VOID
我有一个 Visual Studio 2008 C++ 项目,它在出现异常 错误时使用 Win32Exception 类。 Win32Exception 类如下所示: /// defines an e
假设 GetLastError(和变体)是每线程还是每进程是否正确?如果它是每个进程的问题在多线程应用程序中有些明显,因为无法保证在失败的调用和 GetLastError 之间没有进行其他 Win32
为什么是RegCreateKeyEx()返回 LONG ,而不是设置 DWORD错误代码来自 SetLastError() ? 转换它的 LONG 对我来说安全吗?将值返回给 DWORD然后用 Set
我如何在 php 中使用 getLastError() 检查我的保存方法是否正在插入到 mongo? 我按如下方式设置我的数据库: $this->databaseEngine = $app['mong
如果您有一个大型系统,它会自动显示一个漂亮的窗口来解释捕获的异常,那么能够将错误代码与消息一起显示(以供进一步调查)会很好。但是由于某些函数调用是针对设置错误代码的失败 Windows 函数,而有些是
我是一名优秀的程序员,十分优秀!