2

I'm having this weird problem which I can't really figure our why this is happening. Note: these programs are executed on centOS at the bash command line.

I have two similar C programs which are:

file1.c

#include <stdio.h>

int main()
{
    int a, b;
    printf("Enter two nums\n");
    scanf("%d %d", &a, &b);
    printf("%d", a + b);
}

file2.c is the same as file1.c but in the second printf line, it has \n at the end for the format string.

They are compiled using gcc file1.c and gcc file2.c.

From what I know, if a C program is executed successfully and without errors or a specific exit code using return(X), the program should return 0 thus exit code 0.

But for both files, when I'm running them (and entering 2 numbers to satisfy scanf), I'm getting exit codes 2 and 3 respectively.

looking further for those codes, I found that exit code 2 means "Misuse of shell builtins" and I'm not sure why that is happening. As for exit code 3, I didn't find anything concrete, but since it's not zero it indicates some kind of error, which again, I can't seem to find errors in these short programs.

I'm entering the inputs using the keyboard. eg. '2[Enter]2[Enter]' And checking the exit code using echo $? right after running the programs (after they were compiled of course). look something like this.

$ ./a.out
Enter two nums
2
2
4$

Important note: I can't add 'return 0' in these programs, I'm getting them as a final product and later doing some manipulation with their output. So I can't really change anything about these programs.

Would love your help regarding this issue. Thanks!

AllForCode
  • 49
  • 5
  • 1
    What is the input you give the programs when you run them? How do you run them? What is the output of your programs? And how do you check the exit code? And while copying text as an image is usually inappropriate, this feels like one of the exceptions where an image of your terminal window showing how you run the programs, showing your input and output, and how the exit code is checked. – Some programmer dude May 18 '22 at 06:33
  • 2
    Try adding return 0; to the end of main(). Without that you can't really be relying on the return code to be all that meaningful. – robthebloke May 18 '22 at 06:42
  • 3
    What compiler are you using, and more specifically which version of it? Perhaps it builds with C90 standard where you're required to have an explicit `return` from the `main` function? If you build with e.g. the `-Wall` flag, do you get any warnings? – Some programmer dude May 18 '22 at 06:42
  • Hi, I've edited my question using your feedback, I think it should be more informative – AllForCode May 18 '22 at 06:45
  • 1
    @Someprogrammerdude I'm getting a warning warning: control reaches end of non-void function [-Wreturn-type] } – AllForCode May 18 '22 at 06:50
  • @Someprogrammerdude using std=c99 it does return 0. So yes, it must be that the compiler is old and doesn't add 'return 0' like the newer versions. Thanks! – AllForCode May 18 '22 at 06:54
  • 1
    Related: [return 0 optional](https://stackoverflow.com/questions/4138649/why-is-return-0-optional). – Neil May 18 '22 at 06:56

2 Answers2

3

That warning you get means that you build with a very old version of GCC, at most version 4.9.4, which defaults to C90 standard compliant mode (with GCC extensions).

The implicit return from the main function was added in the C99 standard.

Because there's no return from the main function, you will have undefined behavior.

There are three possible solutions:

  1. Upgrade to a newer version of GCC (it's not up to 12.1) where it defaults to at least C99 mode.
  2. Modify the code to add an explicit return from the main function
  3. Build with the flag -std=c99 which tells the compiler to build according to the C99 standard
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
2

The C Standard makes a special case for the main() function and specifies that it implicitly returns 0 in the absence of a return statement. This was added for C99 to try and work around the very common mistake and ensure a consistent exit code unless explicitly provided via a return statement or a call to exit().

The compiler on your target system does not seem to comply with this rule and probably leaves the return value of the printf call in the register where the caller of main() expects the return value. This is a tentative explanation, but before C99 the behavior was actually undefined, any exit status can be produced.

If you enter 10 and 20, printf outputs 30 and returns 2, the number of bytes written to stdout. If a newline is appended to the format string, the same input will produce 3 bytes, hence a return value of 3. On x86 systems, the return value of printf is set in the ax, eax or rax register (in 16-, 32- and 64-bit modes). If this register is not changed before leaving the main function, the startup code will assume that this value was set in the main function and issue a system call to exit the program with this value as the exit code. The C startup behaves as if main() was called as exit(main(argc, argv, envp)).

Adding a return 0; statement is the correct way to fix this problem. Upgrading the compiler should also fix it. It is actually very surprising that gcc would not add the implicit return 0;, you must be using a very old version or a different compiler hiding behind the same command line (clang does this in macOS, but complies with the C99 standard).

Regarding I found that exit code 2 means "Misuse of shell builtins": this is only a convention used by the shell for its own internal commands. The meaning of the exit status is a matter of convention and should be documented in the program's manual page, but the actual exit status is just the return value of its main function, explicit or implicit or the argument to the exit() call that terminated the program (or _exit(), _Exit(), quick_exit()...)

chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • @chqrlie : May I ask you where you found this information about the number of output bytes being used as the exit code? I wonder in particular what happens, if the program outputs more than 255 bytes - as this is the maximum exit code allowed in the Linux/Unix/MacOS world. – user1934428 May 18 '22 at 07:13
  • 1
    @ chqrlie Sorry, you're correct. thank you for the correction! – AllForCode May 18 '22 at 07:14
  • @user1934428: the exit code is undefined. Read the answer: it is a coincidence that may or may not be the explanation. – chqrlie May 18 '22 at 07:14