Search code examples
clinuxshellgccexit-code

what's the meaning of exit code of program with empty void main()?


I made a simple C program with empty main as given below and compiled it with gcc

void main(){
}

upon execution, it return exit code as 25, and if I add a printf statement,after including stdio.h, it returns exit code 5

what's the meaning of 25 and 5 here and why it's being returned by whatever code that is executed before or after main()? exit code is zero if I use int main() and don't put a return statement.


Solution

  • (Adding on John Bollinger's answer)

    * void main

    The old ISO C Standard (ISO/IEC 9899:1999) stated:

    [main] shall be defined

    • with a return type of int and
      • with no parameters […] or
      • with two parameters […] or equivalent; or
      • in some other implementation-defined manner.

    § 5.1.2.2.1 ¶ 1 of the C Standard

    If the return type is not compatible with int, the termination status returned to the host environment is unspecified.

    § 5.1.2.2.3 ¶ 1

    which indicates that allowing forms that didn't return int was intentional.

    Many compiler's manuals (e.g. Watcom C/C++, IBM VisualAge C/C++, Microsoft Visual C/C++) stated that main may have the return type void so a program with void main() was a conforming program.

    For a long time much code was written with a return type of void. gcc (probably) consider important to be compatible with legacy code and allows void main() but in that case:

    • it gives a warning (warning: return type of ‘main’ is not ‘int’);
    • the return value of the program is undefined.

    References:

    * int main

    int main() {}

    This is undefined in C89/90 and well defined in following versions (where it returns 0).

    * actual value

    On x86 the EAX register is normally used for return values. So

    int main() {}
    

    is compiled to something like:

    main:
            push    rbp
            mov     rbp, rsp
            mov     eax, 0
            pop     rbp
            ret
    

    For

    void main() {}
    

    the simplest action is removing mov eax, 0:

    main:
            push    rbp
            mov     rbp, rsp
            nop
            pop     rbp
            ret
    

    If you add a printf statement:

    #include <stdio.h>
    
    void main()
    {
      printf("1234");
    }
    

    you get:

    .LC0:
            .string "1234"
    main:
            push    rbp
            mov     rbp, rsp
            mov     edi, OFFSET FLAT:.LC0
            mov     eax, 0
            call    printf
            pop     rbp
            ret
    

    The printf call alters the EAX register (returns the number of characters written to the stream, and EAX is used for the return value).