24

What does standard say about main return values range? Say only up to 255?

Because

int main(void){
return 256;
}
echo $? ;  # out 0
1

7 Answers 7

23

The standard doesn't say. 0, EXIT_SUCCESS and EXIT_FAILURE have (sort of) specified meanings. Anything else depends on the implementation.

At the present time, most Unix-based systems only support 8-bit return values. Windows supports (at least) a 32-bit return value. I haven't checked whether 64-bit Windows supports a 64-bit return value, but I rather doubt it, since even 64-bit Windows normally still uses a 32-bit int.

6
  • 2
    on 64-bit Windows I tried cmd /c "exit 4000000000" then echo %errorlevel% and it returns -294967296 => 32-bit
    – phuclv
    Commented Jul 25, 2015 at 13:00
  • The POSIX standard does define this quite clearly: pubs.opengroup.org/onlinepubs/9699919799/functions/_exit.html Commented May 14, 2018 at 11:40
  • @MikeFrysinger: It says: "...the full value shall be available from waitid() and in the siginfo_t passed to a signal handler for SIGCHLD.v", but doesn't say anything about whether that "full value" is 16, 32 or 64 bits. I see no cross reference to a POSIX-specific definition of the size of an int, and the C standard allows any of the above. It may be a decent definition of the other cleanup that needs to happen when shutting down a process, but seems mediocre (at best) with respect to the number of bits in the return value. Commented May 14, 2018 at 13:24
  • While you are correct they don't explicitly dictate the size of an int, both POSIX & the C standard mandate that INT_MAX must be at least 2147483647 (2^31-1) and INT_MIN must be at most -2147483647 (-2^31+1), and that an object of type "int" must be able to represent [INT_MIN, INT_MAX], so I think it's safe to assume that sizeof(int) is (at least) 32-bits on any POSIX compliant system. pubs.opengroup.org/onlinepubs/9699919799/basedefs/… Commented May 15, 2018 at 15:33
  • 1
    You could also look at it like this: the return value of main is an "int". The full value of that, whatever it may be, is defined by POSIX (2016+) to be available to the parent process when using waitid or sigaction/etc...+SA_SIGINFO. Commented May 16, 2018 at 10:11
22

As others have stated, the C & C++ Standards don't constrain return values at all other than to state that

  1. main() returns an int (which is of an implementation defined size), and
  2. zero (or EXIT_SUCCESS) is a successful return and EXIT_FAILURE is a non-successful return.

It does specify that a main() that does explicitly not return a value is treated as if it had returned zero.

In this case, the interpretation of the return value is up to the process that waits on the process to complete (by calling wait(), waitpid(), or waitid()). wait() and waitpid() are the older POSIX functions and they specify that only the least significant eight bits of the return value shall be available to a waiting parent process. The POSIX:2008 standard added waitid() as a generalized wait method that has access to the full exit status of a child process.

After forking off a subprocess, the parent process calls one of the wait*() functions to sleep until the forked process is completed (e.g., returns from main(), calls exit() or abort() or something). The wait() and waitpid() functions return the status by way of a pointer to an integer. The caller extracts the actual exit status using the WIFEXITED(status_val) and WEXITSTATUS(status_val) macros. The latter is defined by POSIX and required to return the low-order 8 bits of the status argument. The waitid() function uses a pointer to a siginfo_t structure to return the process's status information. The si_status member contains the full status value as described in Status Information.

Basically, the values of the exit status are in the eye of the beholder. The ANSI/ISO specifications are open-ended. The POSIX suite has multiple ways to wait on a process to finish and fetch it's exit status. POSIX also defines spawn() as a lighter-weight version of exec() which has its own set of constraints on exit status values. Shells have a habit of further restricting result values -- GNU's bash limits the return status to 7 bits and a POSIX-compliant shell limits exit status values to 8 bits. FWIW, most people agree that restricting your return values to be lower than 64 seems to be safe.

2
  • I tried a small sample program on Ubuntu 21.10 (generic linux 5.13) but imho inside the siginfo_t structure filled by waitid(...) there are no field containing a return value greater than 255 / 1 byte
    – NGI
    Commented Feb 9, 2022 at 6:23
  • 1
    @NGI That's because Linux is broken. The si_status field per POSIX is supposed to contain the full return value: "The exit value in si_status shall be equal to the full exit value (that is, the value passed to _exit(), _Exit(), or exit(), or returned from main()); it shall not be limited to the least significant eight bits of the value." Commented Sep 1, 2022 at 17:47
4

Exit codes are a number between 0 and 255 inclusive on Unix like system. You can return anything but in Linux it's modded 256. Take a peek here for a good explanation on Linux return codes. There is also a Wikipedia article on the topic which talks breifly about exit codes for Windows.

3
  • Saying "modulo" is misleading as it's actually an 8-bit mask. exit(-1) would yield a value of 255 to most callers (since -1&0xff == 255), but -1%256 == -1, not 255. Yes, it goes from signed 32-bit to unsigned 8-bit. Commented May 14, 2018 at 12:05
  • @MikeFrysinger "modulo" is the right term, though. The % operator you're describing here is the remainder of division, but most modern programming languages actually use % for modulo, where this holds true. Commented Apr 12, 2020 at 10:48
  • Modulo is not the right term as I already explained. The fact that % == modulo is not relevant because the operation at hand is not %. Commented Apr 13, 2020 at 15:51
3

The C standard do not impose particular limitation on exit codes, the paragraph about the return value of main delegates to the documentation about the exit() function, which in turn says:

If the value of status is zero or EXIT_SUCCESS, an implementation-defined form of the status successful termination is returned. If the value of status is EXIT_FAILURE, an implementation-defined form of the status unsuccessful termination is returned. Otherwise the status returned is implementation-defined.

which, apart from the EXIT_SUCCESS/EXIT_FAILURE guidelines, basically means "do whatever you want". :)

As said in one comment, the fact that on POSIX systems only the lower 8 bits of the exit code are actually considered is just a UNIXism, deriving from how the wait syscall is designed (the exit status has to be packed in the lower 8 bits of the wait return value), and has nothing to do with the C standard.

A counterexample is Windows, where the whole value passed to exit/return is considered (as long as it's not bigger than a DWORD1, but I don't think they'll ever make int be bigger than a DWORD, it would break a lot of code).


1. Because the GetExitCodeProcess parameter reserved for returning this value is a DWORD *.

1
  • in fact the ExitProcess function receives a UINT
    – phuclv
    Commented Mar 31, 2019 at 11:14
2

On Unix, the wait system call sets a status value of type int packed as a bitfield with various types of child termination information. If the child terminated by exiting (as determined by the WIFEXITED macro; the usual alternative being that it died from an uncaught signal), SUS specifies that the lower 8 bits of the status value contain the exit status; this can be retrieved using the WEXITSTATUS macro in wait.h. As such, on Unix exit statuses are restricted to values 0-255, the range of an unsigned 8-bit integer.

Unix like systems typically use a convention of zero for success and non zero for error. Some conventions have developed as to the relative meanings of various error codes; for example GNU recommend that codes with the high bit set be reserved for serious errors, and FreeBSD have documented an extensive set of preferred interpretations.

C99 standard defines only 0 and 1. However, allows other values to be used.

See Exit Status wiki for more.

2
  • 6
    I don't recall ever seeing the value of 1 specified anywhere in the standard. Only 0, EXIT_SUCCESS, and EXIT_FAILURE are explicitly called out as status values in the ANSI/ISO Standard.
    – D.Shawley
    Commented Mar 1, 2011 at 1:03
  • 2
    @D.Shawley: You are right. But I never saw EXIT_SUCCESS to be something different from #define EXIT_SUCCESS 0 or EXIT_FAILURE from #define EXIT_FAILURE 1.
    – user405725
    Commented Mar 1, 2011 at 22:41
0

You return type int. You should be able to return any value that can be stored in an int. The exact size of an int is implementation-dependent, so I can't give you an exact range.

5
  • That being said, your shell might have a limited range of return values that it supports. This isn't part of the C standard, however.
    – bta
    Commented Mar 1, 2011 at 0:35
  • Even though return type is int, only lower 8 bits contain exit status.
    – user405725
    Commented Mar 1, 2011 at 0:38
  • 1
    @Vlad: it's just a UNIXism, the standard does not say anything about it. Commented Mar 1, 2011 at 0:39
  • @Vlad Lazarenko- That is not true according to the C standard. That is POSIX-specific behavior. The OP asked about what the standard specifies.
    – bta
    Commented Mar 1, 2011 at 0:43
  • I actually told what C standard specifies, 0 and 1 :-) Since question was asked in unix scope ($?), I said why 0-255...
    – user405725
    Commented Mar 1, 2011 at 0:45
0

5.1.2.2.3 Program termination 1 If the return type of the main function is a type compatible with int, a return from the initial call to the main function is equivalent to calling the exit function with the value returned by the main function as its argument; 10) reaching the } that terminates the main function returns a value of 0. If the return type is not compatible with int, the termination status returned to the host environment is unspecified

http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf

ie, there is no requirement for it to return anything. However it strongly states just up from that what the usual definitions are. Almost implying they are they standard, but has a get out of jail free card which means it can be anything.

Not the answer you're looking for? Browse other questions tagged or ask your own question.