<p>If yes, on which operating system, shell or whatever?</p>

<p>Consider the following java program (I'm using java just as an example, any language would be good for this question, which is more about operation systems):</p>

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

<p>Running it on Linux and bash, it returns always values less equal 255, e.g. (<code>echo $?</code> prints the exit code of the previous executed command)</p>

<pre><code>&gt; java ExitCode 2; echo $?
2

&gt; java ExitCode 128; echo $?
128

&gt; java ExitCode 255; echo $?
255

&gt; java ExitCode 256; echo $?
0

&gt; java ExitCode 65536; echo $?
0
</code></pre>

<hr>

<p>EDITED: the (only, so far) answer below fully  explain what happens on UNIXes. I'm still wondering about other OSes.</p>

Using
```
wait()
```
or
```
waitpid()
```
It is not possible on Unix and derivatives using POSIX functions like
```
wait()
```
and
```
waitpid()
```
.  The exit status information returned consists of two 8-bit fields, one containing the exit status, and the other containing information about the cause of death (0 implying orderly exit under program control, other values indicating that a signal killed it, and indicating whether a core was dumped).
Using
```
sigaction()
```
with
```
SA_SIGINFO
```
If you work hard, and read the POSIX specification of
```
sigaction()
```
and
```
<signal.h>
```
and
Signal Actions
, you will find that you can get hold of the 32-bit value passed to
```
exit()
```
by a child process.   However, it is not completely straight-forward.
```
```
#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();
}
```
```
When run (program
```
sigexit73
```
compiled from
```
sigexit73.c
```
), this produces output like:
```
```
$ 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)
$
```
```
With the one millisecond call to
```
nanosleep()
```
removed, the output is apt to look like:
```
```
$ 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)
$
```
```
Note that there are only three lines starting
```
Signal
```
here, and also only three lines ending
```
waited
```
; some of the signals and exit statuses are lost.  This is likely to be because of timing issues between the
```
SIGCHLD
```
signals being set to the parent process.
However, the key point is that 4 bytes of data can be transmitted in the
```
exit()
```
status when the code uses
```
sigaction()
```
,
```
SIGCHLD
```
,
```
SA_SIGINFO
```
to track the status.
Just for the record, the testing was performed on a MacBook Pro running macOS Mojave 10.14.6, using GCC 9.2.0 and XCode 11.3.1.  The code is also available in my
SOQ
(Stack Overflow Questions) repository on GitHub as file
```
sigexit73.c
```
in the
src/so-1843-7779
sub-directory.