42 Stimmen

ExitCodes größer als 255, möglich?

Wenn ja, auf welchem Betriebssystem, welcher Shell oder was auch immer?

Betrachten Sie das folgende Java-Programm (ich verwende Java nur als Beispiel, jede Sprache wäre gut für diese Frage, die sich mehr um Betriebssysteme dreht):

public class ExitCode {
    public static void main(String args[]) {
        System.exit(Integer.parseInt(args[0]));
    }
}

Unter Linux und Bash liefert es immer Werte kleiner gleich 255, z.B. ( echo $? gibt den Exit-Code des zuvor ausgeführten Befehls aus)

> java ExitCode 2; echo $?
2

> java ExitCode 128; echo $?
128

> java ExitCode 255; echo $?
255

> java ExitCode 256; echo $?
0

> java ExitCode 65536; echo $?
0

BEARBEITET: die (bisher einzige) Antwort unten erklärt vollständig, was unter UNIX passiert. Ich frage mich immer noch, was mit anderen Betriebssystemen passiert.

0 Stimmen

Dies liegt daran, dass eine vorzeichenlose kurze Ganzzahl (8 Bit) zurückgegeben wird. 0000000 = 0 11111111 = 255

40voto

Jonathan Leffler Punkte 694013

使用方法 wait() o waitpid()

Unter Unix und Derivaten ist es nicht möglich, mit POSIX-Funktionen wie wait() y waitpid() . Die zurückgegebene Exit-Status-Information besteht aus zwei 8-Bit-Feldern, von denen eines den Exit-Status und das andere Informationen über die Todesursache enthält (0 bedeutet, dass das Programm ordnungsgemäß unter Programmkontrolle beendet wurde, andere Werte zeigen an, dass es durch ein Signal beendet wurde, und geben an, ob ein Kern ausrangiert wurde).

使用方法 sigaction() con SA_SIGINFO

Wenn Sie hart arbeiten und die POSIX-Spezifikation von sigaction() y <signal.h> y Signal-Aktionen werden Sie feststellen, dass Sie den 32-Bit-Wert, der an exit() durch einen Kindprozess. Dies ist jedoch nicht ganz einfach.

#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>

static siginfo_t sig_info = { 0 };
static volatile sig_atomic_t sig_num = 0;
static void *sig_ctxt = 0;

static void catcher(int signum, siginfo_t *info, void *vp)
{
    sig_num = signum;
    sig_info = *info;
    sig_ctxt = vp;
}

static void set_handler(int signum)
{
    struct sigaction sa;
    sa.sa_flags = SA_SIGINFO;
    sa.sa_sigaction = catcher;
    sigemptyset(&sa.sa_mask);

    if (sigaction(signum, &sa, 0) != 0)
    {
        int errnum = errno;
        fprintf(stderr, "Failed to set signal handler (%d: %s)\n", errnum, strerror(errnum));
        exit(1);
    }
}

static void prt_interrupt(FILE *fp)
{
    if (sig_num != 0)
    {
        fprintf(fp, "Signal %d from PID %d (status 0x%.8X; UID %d)\n",
                sig_info.si_signo, (int)sig_info.si_pid, sig_info.si_status,
                (int)sig_info.si_uid);
        sig_num = 0;
    }
}

static void five_kids(void)
{
    const int base = 0xCC00FF40;
    for (int i = 0; i < 5; i++)
    {
        pid_t pid = fork();
        if (pid < 0)
            break;
        else if (pid == 0)
        {
            printf("PID %d - exiting with status %d (0x%.8X)\n",
                   (int)getpid(), base + i, base + i);
            exit(base + i);
        }
        else
        {
            int status = 0;
            pid_t corpse = wait(&status);
            if (corpse != -1)
                printf("Child: %d; Corpse: %d; Status = 0x%.4X - waited\n", pid, corpse, (status & 0xFFFF));
            struct timespec nap = { .tv_sec = 0, .tv_nsec = 1000000 }; // 1 millisecond
            nanosleep(&nap, 0);
            prt_interrupt(stdout);
            fflush(0);
        }
    }
}

int main(void)
{
    set_handler(SIGCHLD);
    five_kids();
}

Bei der Ausführung (Programm sigexit73 zusammengestellt von sigexit73.c ), ergibt dies eine Ausgabe wie:

$ sigexit73
PID 26599 - exiting with status -872349888 (0xCC00FF40)
Signal 20 from PID 26599 (status 0xCC00FF40; UID 501)
Child: 26600; Corpse: 26599; Status = 0x4000 - waited
PID 26600 - exiting with status -872349887 (0xCC00FF41)
Signal 20 from PID 26600 (status 0xCC00FF41; UID 501)
Child: 26601; Corpse: 26600; Status = 0x4100 - waited
PID 26601 - exiting with status -872349886 (0xCC00FF42)
Signal 20 from PID 26601 (status 0xCC00FF42; UID 501)
Child: 26602; Corpse: 26601; Status = 0x4200 - waited
PID 26602 - exiting with status -872349885 (0xCC00FF43)
Signal 20 from PID 26602 (status 0xCC00FF43; UID 501)
Child: 26603; Corpse: 26602; Status = 0x4300 - waited
PID 26603 - exiting with status -872349884 (0xCC00FF44)
Signal 20 from PID 26603 (status 0xCC00FF44; UID 501)
$

Mit dem eine Millisekunde dauernden Aufruf von nanosleep() entfernt wird, kann die Ausgabe wie folgt aussehen:

$ sigexit73
sigexit23
PID 26621 - exiting with status -872349888 (0xCC00FF40)
Signal 20 from PID 26621 (status 0xCC00FF40; UID 501)
Child: 26622; Corpse: 26621; Status = 0x4000 - waited
PID 26622 - exiting with status -872349887 (0xCC00FF41)
PID 26623 - exiting with status -872349886 (0xCC00FF42)
Signal 20 from PID 26622 (status 0xCC00FF41; UID 501)
Child: 26624; Corpse: 26623; Status = 0x4200 - waited
Signal 20 from PID 26623 (status 0xCC00FF42; UID 501)
Child: 26625; Corpse: 26622; Status = 0x4100 - waited
PID 26624 - exiting with status -872349885 (0xCC00FF43)
PID 26625 - exiting with status -872349884 (0xCC00FF44)
$

Beachten Sie, dass es nur drei Zeilen gibt, die mit Signal hier, und auch nur drei Zeilen mit der Endung waited Einige der Signale und Ausstiegsstatus sind verloren gegangen. Dies liegt wahrscheinlich an Zeitproblemen zwischen dem SIGCHLD Signale, die an den übergeordneten Prozess gesendet werden.

Der springende Punkt ist jedoch, dass 4 Byte Daten in der exit() Status, wenn der Code mit sigaction() , SIGCHLD , SA_SIGINFO um den Status zu verfolgen.

Nur für das Protokoll, die Tests wurden auf einem MacBook Pro mit macOS Mojave 10.14.6 durchgeführt, mit GCC 9.2.0 und XCode 11.3.1. Der Code ist auch verfügbar in meinem SOQ (Stack Overflow Questions) Repository auf GitHub als Datei sigexit73.c im src/so-1843-7779 Unterverzeichnis.

17voto

Michael Ratanapintha Punkte 38036

Unter modernen Windows-Betriebssystemen sind das Betriebssystem selbst und die Standardkonsolen-Shell ( CMD.EXE ), akzeptieren und zeigen Exit-Codes über mindestens den gesamten Bereich von 32-Bit-Ganzzahlen mit Vorzeichen an. Wenn Sie Ihr obiges Beispiel in CMD.EXE gibt die von Ihnen gewünschten Exit-Codes an:

> java ExitCode 2
> echo %errorlevel%
2

> java ExitCode 128
> echo %errorlevel%
128

> java ExitCode 255
> echo %errorlevel%
255

> java ExitCode 256
> echo %errorlevel%
256

> java ExitCode 65536
> echo %errorlevel%
65536

Windows kennt weder das Konzept der Unix-Signale noch versucht es, den Exit-Code zu missbrauchen, um zusätzliche Informationen hinzuzufügen. Solange Ihre Shell (oder das Programm, das den Exit-Code ausliest) dies nicht tut, sollten Sie die zurückgegebenen Exit-Codes zurückerhalten. Glücklicherweise bewahren Programme, die Microsofts C-Laufzeitumgebung verwenden (einschließlich aller mit MS Visual C++ kompilierten Programme), den Exit-Code von beendeten Prozessen unverändert auf.

1voto

Veynom Punkte 3951

Windows hat viel mehr Exit-Codes, über 14.000. (Ich bin sicher, dass Sie einige davon schon oft auf Ihrem eigenen Bildschirm gesehen haben).

Jetzt kommt's:

11 Stimmen

Sie sprechen von den Fehlercodes, die von den Standard-Windows-APIs zurückgegeben werden. Der OP möchte wissen, welche Fehlercodes er für sein eigenes Programm zurückgeben kann.

3 Stimmen

Nein, Windows unterstützt 32-Bit-Exit-Code => über 4 Milliarden

0 Stimmen

Man hätte auch "über 9000" sagen können!

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X