首页 > 其他分享 >return -1 和 255

return -1 和 255

时间:2023-01-15 13:13:56浏览次数:47  
标签:status Shell return pid exit include 255

环境

  • 系统:macOS M1

  • Shell:Zsh

  • 编译器:clang++ 13.1.6

return -1 和 255

一个简单的 C++ 小程序:

int main() { return -1; }

编译执行后,查看程序的退出码为 255:

❯ echo $?
255

为什么程序里返回的是 -1,但是系统中查看的退出码却是 255 呢?

分析

我们知道如果是非零的退出码,表示命令执行失败,尝试更多的情况:

Return Exit Code
-1 255
-2 254
-10 246
1 1

基于此,我们先做一些猜测:

  1. 退出码可能是一个 unsigned 的类型,长度可能是 1 个字节。

  2. 上述情况中,-1 和 255, -2 和 254,以及 -10 和 246 之间应该存在某种规律,可能是一种强制类型转换。

针对以上猜测,我们需要进一步了解负数在内存中是如何存储的。

负数的表示

在计算机中,数值统一使用补码来表示和存储。其中,正数的补码和其原码相同,负数的补码是将其原码除符号位外,其余取反后加 1。

以 -1 为例,假设它为 signed char 类型,那么它的原码为 1000 0001,补码为 1111 1111,如果将其强制转换为 unsigned char 类型,它的十进制表示的就是 255。

其它情况的转换结果如下:

signed char 原码 补码 unsigned char
-1 1000 0001 1111 1111 255
-2 1000 0010 1111 1110 254
-10 1000 1010 1111 0110 246
1 0000 0001 0000 0001 1

我们也可以使用程序计算上述结果,以 Python 为例:

>>> import array
>>> arr = array.array("b", [-1, -2, -10, 1])
>>> arr_v = memoryview(arr)
>>> arr_v.cast("B").tolist()
[255, 254, 246, 1]

fork 和 exec

简单来说,当我们在 Shell 中执行上述编译后的二进制可执行文件时,Shell 会先 fork 出一个子进程,然后在子进程中执行命令,命令的退出状态会再被父进程(Shell)收集。

不包含 Shell 的内建命令,如 cdalias 等,这些内建命令不会创建子进程。

收集命令结果

Shell 本质上也是一个程序,可以通过 C 语言库函数中的 wait() 方法收集子进程返回的结果。

pid_t   wait(int *status)

其中,status 的主要字段结构如下:

15        8        7        6       0
+-----------------------------------+
|  退出码  | core dump 标识位 |  信号  |
+-----------------------------------+

一般而言,程序退出的方式有两种:

  1. 程序正常结束,例如:return 或者 exit 等;

  2. 程序异常终止,例如:CTRL + C 或者 kill 等;

我们可以通过一些程序对上述两种情况做一些测试。

  1. 程序正常结束:
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

int main() {
  pid_t c_pid;
  int status;

  c_pid = fork();
  if (c_pid == 0) {
    exit(-10); /* 子进程退出 */
  } else {
    wait(&status); /* 收集子进程的状态 */
  }

  printf("Child exit code: %d\n", WEXITSTATUS(status));

  return 0;
}

编译执行上述程序:

Child exit code: 246

这里我们使用了宏函数 WEXITSTATUS 来获取退出码,在我的系统中,它的实际含义为:

#define _W_INT(w)       (*(int *)&(w))
#define WEXITSTATUS(x)  ((_W_INT(x) >> 8) & 0x000000ff)
  1. 程序异常终止:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

int main() {
  pid_t c_pid;
  int status;

  c_pid = fork();
  if (c_pid == 0) {
    for (;;) /*死循环*/
      ;
  } else {
    kill(c_pid, SIGKILL);

    wait(&status);
  }

  printf("Child exit signal: %d\n", WTERMSIG(status));

  return 0;
}

编译执行上述程序:

Child exit signal: 9

这里我们向子进程发送 SIGKILL 信号,杀死进程,和 kill -9 命令的效果相似。并且,可以通过 WTERMSIG 宏函数解析出导致进程终止的信号值。

俗成的约定

类似 HTTP 服务中的 404、501 这样的状态码,针对 Shell 中命令的退出码也有一些默认俗成的约定

Exit Code Number Meaning Example Comments
1 Catchall for general errors var1 = 1/0 Miscellaneous errors, such as "divide by zero" and other impermissible operations
126 Command invoked cannot execute /dev/null Permission problem or command is not an executable
127 "command not found" illegal_command Possible problem with $PATH or a typo
128 Invalid argument to exit exit 3.14159 exit takes only integer args in the range 0 - 255 (see first footnote)
128+n Fatal error signal "n" kill -9 $PPID of script $? returns 137 (128 + 9)
130 Script terminated by Control-C Ctl-C Control-C is fatal error signal 2, (130 = 128 + 2, see above)
255* Exit status out of range exit -1 exit takes only integer args in the range 0 - 255

标签:status,Shell,return,pid,exit,include,255
From: https://www.cnblogs.com/luizyao/p/17053342.html

相关文章

  • Sub-process /usr/bin/dpkg returned an error code (1)解决方案
    第一步:创建一个干净的dpkg文件夹sudomv/var/lib/dpkg/info/var/lib/dpkg/info.bak//先将info文件夹更名sudomkdir/var/lib/dpkg/info//再新建一个新的info文件夹......
  • HarmonyOS初探03——DevEco Studio创建应用问题ERROR Unable to tunnel through proxy
    问题在内网环境下首次使用DevEcoStudio创建应用时,可能会报如下问题:ERROR:Unabletotunnelthroughproxy.Proxyreturns"HTTP/1.1403Openproxy_Blocked_URL_list"我......
  • bzoj 2554 Color 期望DP
    期望DP枚举最终能成为哪个颜色,把这个颜色看做白球,其余颜色看成黑球。最后分别把每种颜色的期望加起来就行。考虑当前有i个白球,全变成白球期望步数设为f[i]一次操作可能......
  • 【参考答案】java基础练习:循环结构(while、do...while、for、break、continue、return
    while while实现:输出比i(i=5)小的正整数packagecom.qzcsbj;publicclassTest{publicstaticvoidmain(String[]args){inti=5;while(......
  • 存储过程 RETURN语句
     1、RETURN如果没有使用表达式,RETURN命令用于告诉这个函数已经完成执行了,如示例2.如果返回标量类型,那么可以使用任何表达式。 示例1:带有表达式returnCREATEOR......
  • ()=>({})等同于()=>( return {})
    首先这里用的时ES6的箭头函数 ()=>{}而此种写法()=>({})等同于()=>{return{}}其实这里我们可以直接使用config:{}就可以,为什么还要多以一举,用函数来返回呢,原因是假如......
  • CVE-2020-2551
    前言2020年1月15日,Oracle发布了一系列的安全补丁,其中OracleWebLogicServer产品有高危漏洞,漏洞编号CVE-2020-2551,CVSS评分9.8分,漏洞利用难度低,可基于IIOP协议执行......
  • 【转】nginx调优之使用return代替rewrite做重定向
    使用return代替rewrite做重定向转自:https://www.jianshu.com/p/26dc6c2b5f43原文地址:https://github.com/trimstray/nginx-admins-handbook/blob/master/doc/RULES.md#be......
  • [ABC255F] Pre-order and In-order 题解
    [ABC255F]Pre-orderandIn-orderSolution目录[ABC255F]Pre-orderandIn-orderSolution更好的阅读体验戳此进入题面SolutionCodeUPD更好的阅读体验戳此进入题面给......
  • AtCoder Beginner Contest 255 题解
    AtCoderBeginnerContest255Solution目录AtCoderBeginnerContest255Solution更好的阅读体验戳此进入题面链接题面Luogu链接abcd跳了[ABC255E]LuckyNumbers题......