使用 GetLastError() 的真正正确的方法(时间)是什么?
What is the REALLY correct way (time) to use GetLastError()?
在对Stack Overflow进行了扩展的争论之后(现在已经由Powers-that-Be清理了(,出现了一个问题,即何时应该真正调用GetLastError
函数。
注意:这不是一个关于风格的问题,只是关于: (a( 在"非纯粹主义"守则的情况下,标准保证(或不保证(什么; (b( 就安全winapi
规划而言,什么是"最佳做法"。
这里有一个例子(改编自那里发布的原始问题(:
#include <windows.h>
#include <stdio.h>
#include <iostream>
//#define PURIST 1
using namespace std;
int main()
{
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
SMALL_RECT wSize = { 0,0,60,20 }; // Works on my screen!
if (hConsole == nullptr) {
cout << "Console Handle is Null" << endl;
return 1;
}
else {
char message[256];
if (!SetConsoleWindowInfo(hConsole, TRUE, &wSize)) {
#ifdef PURIST
// 'Purist' code ...
DWORD eCode = GetLastError();
sprintf(message, "SetConsoleWindowInfo failed; code = %d!", eCode);
#else
// More normal code ...
sprintf(message, "SetConsoleWindowInfo failed; code = %d!", GetLastError());
#endif
}
else {
strcpy(message, "SetConsoleWindowInfo call succeeded!");
}
cout << message << endl;
}
getchar(); // Just to stop console closing!
return 0;
}
显然,"纯粹主义"方法将始终正常工作!但是,c++
语言标准是否保证"正常"方法也有效?(也就是说,是否可以确定GetLastError()
作为sprintf
参数将是测试SetConsoleWindowInfo()
返回值后执行的第一个代码?
PS:请不要对代码的质量过于苛刻地评判我!正如我所说,这是对原始问题的改编。
编辑:一个更典型的情况(我在Windows应用程序中经常使用(如下所示:
if (<WinApi call failed>) {
TCHAR eText[256];
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(), 0, eText, 255, nullptr);
// Do something with eText, etc. ...
return <error code>;
}
但同样,GetLastError()
是唯一的非常量论点。
我将这个问题分为两个独立的问题:
-
"普通代码"示例是否按预期工作?
是的,此确切代码将按预期工作。其他函数参数是内置类型,即使未定义顺序函数参数的计算,它们都不会干扰GetLastError
调用。 -
"普通代码"示例是调用
GetLastError
的正确方法吗?
事实并非如此,即使运行此代码会产生预期的结果。这样做的原因是,使用GetLastError
作为函数参数引入了对其他函数参数的隐式约束,即它们必须没有最后错误更改的副作用。这使得代码更容易出错,更难维护。
因此,经验法则是在调用其他函数或创建/销毁对象之前将最后一个错误值存储在某个变量中。
非纯粹主义的方式在这里很好
调用函数时(无论函数是否内联,以及是否使用显式函数调用语法(,与任何参数表达式或指定被调用函数的后缀表达式关联的每个值计算和副作用都在执行被调用函数主体中的每个表达式或语句之前进行排序。
规则 3,我认为这对应于 C++17 标准草案版本中的 §8.2.2.5。
在这种情况下,没有任何其他有副作用的论点。
但请注意,它是脆弱的,如果有人做了一些顽皮的事情,比如
#define sprintf (log_call_to_sprintf(), sprintf)
你运气不好。
让我们有下一个代码片段
if (<WinApi call failed>) {
SomeApiCall(arg<1>, .., GetLastError(), .., arg<n>);
}
并假设以下条件:
SomeApiCall
不是扩展到其他内容的宏 - 这是 正是一些函数调用- 函数的所有参数 (
arg<1>
...arg<n>
(,除GetLastError()
外,仅使用内部C/C++语言表达式,计算时没有任何 外部函数调用(包括语言支持库( 参数中不存在任何东西,什么会导致硬件异常, 如除以零、参考内存除以指针等
这不是关于编码风格的问题
例如此调用
SomeApiCall( "some text", GetLastError(), 8);
符合 2 和 3
在这种情况下,我们可以说GetLastError()
将在线程的最后一个错误代码值可以更改之前调用,在<WinApi call failed>
之后。 因为:
- 线程的最后一个错误代码只能作为某些结果进行更改 视窗 API 调用
- 函数(
SomeApiCall
(的所有参数在执行被调用体中的每个表达式或语句之前计算 功能 - 所以在
<WinApi call failed
>和SomeApiCall
之间只存在arg<1>
, ..,GetLastError()
, ..,arg<n>
- 到期 2 和 3 - 没有任何直接或间接(在异常处理程序中( Windows API 调用,因为C/C++语言不了解 Windows API并且不能通过自调用它(没有一些外部的 语言调用,包括语言支持库(
- 所以在
<WinApi call failed
>和GetLastError()
之间打电话 - 没有任何 视窗 API 调用 - 由于最后一个错误代码的结果值不会在
<WinApi call failed
>和GetLastError()
通话
- 在两台机器之间进行时间戳的最佳c++chrono函数是什么
- C++代码的 C# 日期时间等效项是什么?
- 使用 GetLastError() 的真正正确的方法(时间)是什么?
- 这种日期和时间格式是什么?
- 此代码中运行时间错误的原因是什么
- 在 C++11 中表示日内时间 HH:MM:SS 的最佳方法是什么?
- 在 C++11 中获取当前时间的最快方法是什么
- 从给定的 IPv6:端口列表中搜索 IPv6:端口组合的最快搜索算法是什么 O(1) 时间一致性
- 该功能检测循环链接列表的时间复杂性是什么?
- 语言环境"en_US"中 std::time_get::get_time() 的正确时间格式是什么?
- 计算"copying a binary file in c++ on linux"消耗时间的最佳方法是什么?
- 在内存使用或编译时间方面更好的是什么
- 在 C++11 中,获取系统即时报价/时间的最快方法是什么?
- 标准::时间纪元是什么时候?
- 为什么铬执行时间::现在?好处是什么
- 形成自定义标准::时间::d和标准::比率的最佳方法是什么?
- 主流C++编译器中 GC 实现的时间线是什么?
- 在C++11中解析毫秒日期时间的最佳方法是什么
- 对于大型C++项目,建议的 Eclipse CDT 配置是什么(索引器需要很长时间)
- C++中strstr()函数的时间复杂度、空间复杂度和算法是什么