为什么sys.exit4294967295将%ERRORLEVEL%设置为-1?

问题描述

在弄乱调用Python脚本的批处理脚本时偶然发现了这一点。

在Python脚本中,我正在调用sys.exit(-1),它将%ERRORLEVEL%设置为4294967295。在读取Windows使用32位无符号整数之后,我将其更改为sys.exit(4294967295),但是现在%ERRORLEVEL%是-1。

它为什么做逆运算? sys.exit(-1)之所以有意义,是因为其(2 ^ 32)-1并与回绕一起存储,但是为什么使用32位无符号整数的最大值转换为-1?是C里面的东西吗?

解决方法

负整数值可以使用基数补码表示。因此,相同的基础四字节值0xFFFFFFFF可以表示无符号的32位值4294967295或有符号的32位two's complement值-1。这仅取决于如何在上下文中解释字节,这包括使用带符号对无符号指令,例如在x86 ISA中使用JG(如果有更大符号,则跳转)与{{1} }(如果高于则跳-未签名)。

CMD等待进程退出时,它通过GetExitCodeProcess获取退出状态,并将其保存为32位带符号整数JA。 ( module_name!symbol_name 是调试器(例如windbg或cdb)如何在已加载的模块中引用全局符号名称的方法。)即使Windows在API级别返回,Windows仍将退出状态解释为带符号整数cmd!LastRetCode,它是DWORD的C typedef。

通常,Windows中的进程退出状态是一个无符号的16位值,范围为0-65535。通常是通过失败,即EXIT_SUCCESS(0)或unsigned long(1)。但是,如果Windows程序异常终止(例如未处理的异常),则状态码通常是EXIT_FAILURE值,它是一个32位带符号整数,将警告和故障表示为负值。例如,访问冲突为NTSTATUS(0xC0000005或-1073741819)。

当程序异常终止时,批处理脚本可能需要特殊处理。可以使用STATUS_ACCESS_VIOLATION表达式测试最后的退出状态,如果最后的退出状态等于或大于指定的数字,则为true。例如:

errorlevel <number>

CMD本身具有特殊处理,可以为C:\>cmd /c exit -1073741819 C:\>if errorlevel 0 (echo normal exit) else (echo abnormal exit) abnormal exit 打印“ ^ C”(0xC000013A或-1073741510),退出状态表示未处理的控制台控制事件,其中包括未处理的Ctrl + C(取消)和Ctrl +打破。例如:

STATUS_CONTROL_C_EXIT

除了C:\>cmd /c exit -1073741510 ^C 检查外,CMD还具有内置的errorlevel环境变量。内置环境变量实际上并没有存储在流程环境块中。它们作为默认值提供。在调试器中,您可以观察到CMD调用%ERRORLEVEL%来获取环境变量的值。此函数首先尝试WinAPI cmd!GetEnvVar,该API返回实际的过程环境变量(例如GetEnvironmentVariableW)或操作系统内置变量之一(例如PATH__APPDIR__)。如果__CD__找不到“ ERRORLEVEL”,则GetEnvironmentVariableW默认为内置值,即通过GetEnvVar转换为字符串的LastRetCode值,格式为字符串{{ 1}}(即带符号的十进制整数)。例如:

StringCchPrintfW

CMD还将最后一个退出状态设置为"%d"(由于名称以“ =”开头,因此通常处于隐藏状态),该退出状态为无符号32位值,格式为填充零的十六进制数字。如果退出状态是可打印的ASCII序数,范围为32-126,则CMD还将设置C:\>cmd /c exit -1 C:\>echo %errorlevel% -1 C:\>set errorlevel=foo C:\>echo %errorlevel% foo 。无论出于何种原因,CMD都将它们存储为真实环境变量,这些变量将由子进程继承。例如,对于退出状态为65(即0x41,即ASCII序数“ A”):

%=ExitCode%

关于Python中的%=ExitCodeAscii%,请注意C:\>cmd /c exit 65 C:\>python -q >>> import win32api >>> win32api.GetEnvironmentVariable('=ExitCode') '00000041' >>> win32api.GetEnvironmentVariable('=ExitCodeAscii') 'A' (及其下的sys.exit(4294967295))将退出状态作为已签名的Python整数处理,该整数被转换为C {{1} }的范围为-2147483648至2147483647。使用此范围之外的值将导致转换失败,并将退出状态设置为-1。请参阅在GitHub上发布的源代码中的_Py_HandleSystemExit。碰巧4294967295(0xFFFFFFFF)是-1的二进制补码表示形式,但是对于任何其他不受支持的值,您将得到相同的结果。例如:

sys.exit(status)

正常退出状态是0表示成功,1表示失败,包括将错误消息打印到stderr时:

raise SystemExit(status)

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...