views:

262

answers:

5

I have written a program that prints a table. I have not included the return syntax in the main function, but still whenever I type echo $? it displays 12.

My source code :

#include <stdio.h>


int main(void)
{
    int ans,i,n;
    printf("enter the no. : ");
    scanf("%d",&n);

    for(i=1;i<=10;i++)
    {
        ans = n*i;
        printf("%d * %d = %d\n",n,i,ans);
    }
}

I have not written return 12, but still it returns 12 every time I execute the program.

Thanks.

+2  A: 

undefined behaviour

swegi
From 5.1.2.2.3 Program termination: "If the return type of the main function is a type compatible with int ... reaching the } that terminates the main function returns a value of 0". But that specification seems to be new in `c99` (not in `ansi`).
jleedev
@jleedev: 'C89` text is similar: "If the } that terminates the main function is reached, the termination status returned to the host environment is unspecified." ( src: http://www.vmunix.com/~gabor/c/draft.html )
pmg
@pmg: I don't find that very similar. One of them claims implementation specific behavior, the other forces are return of `0`.
Jens Gustedt
@pmg: That is not the C89 spec. If nothing else, the fact that it references IEC 559:1993 gives it away :-).
James McNellis
+2  A: 

If you're at all familiar with assembly language, you may recall that the "return value" of a function is passed through the EAX register.

In this case, the return value is being read from EAX. Which, in this case, happens to be 12.

However, you're not explicitly setting this value, it's simply an artifact from the rest of the code (or perhaps just chance).

As has been said, this is definitely undefined behavior. If you are simply curious why this results, please consider this explanation.

But do not, under any circumstances, attempt to intentionally use this value as anything meaningful.

KevenK
This is restricted to x86 architectures. They may be the most common, but stating it as a universal fact is definitely incorrect.
Ben Voigt
No this is not undefined behavior. For C89 it is implementation specific and for C99 `0` must be returned.
Jens Gustedt
Well on ARM there the same can be said about r0
doron
@doron: That's why in my answer, which I posted before seeing this one (they're barely a minute apart), I used the generic phrase "register used for return values". On x86 that's EAX, on ARM it's r0, and most other architectures have a register similarly listed in the ABI as designated for return values.
Ben Voigt
+15  A: 

As swegi says, it's undefined behavior. As Steve Jessop et al say, it's implementation-defined before C89, and specified in C99 (the observed behavior is non-conformant to C99)

What actually happens in most environments is that the return value from the last printf is left in the register used for return values.

So it'll be 11 for n == 0, 12 if n is one digit, 14 for two digit n, 16 for three digit n, etc.

Ben Voigt
It’s actually unspecified behavior.
jleedev
+1: nice platform-neutral answer (who has a real stack-based machine? ;))
snemarch
(-1, well let's see) because it is not undefined behavior, but in C89 it is implementation specific and in C99 the behavior that is observed is clearly not conforming. (+1 for a nice explanation what is happening, well you are lucky)
Jens Gustedt
hey i never thort of this, nice
Matt Joiner
A: 

Your program is causing undefined behavior by not returning anything when it should, thus the caller will generally grab what ever the value of the eax register(on x86, rax on x64) is at the time of the procedure return, which is generally rubbish from the last use of eax(by functions returning values or just register based vars), in this case its probably the amount of char's that printf has written to the stdout buffer

Necrolis
+9  A: 

Answering because all the existing answers say that it's undefined behaviour, which is not true, so I have nothing I can upvote.

In C89 (thanks to pmg for the reference to a draft standard), 5.1.2.2.3:

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. If the } that terminates the main function is reached, the termination status returned to the host environment is unspecified.

In C99, quoting from n1256, 5.1.2.2.3:

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; 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.

So, it's not "undefined behaviour": it behaves as if the main function returns, but in C89 the value returned is not specified by the standard. For your example program, on your implementation, the value returned appears to consistently be 12, presumably for the reason Ben Voigt says. Since you're on linux, it's probably not a big change to compile your code as C99 (or anyway, compile it using gcc's almost-compliant C99 mode).

For any function that returns a value, other than main, it is undefined behaviour, unless the caller doesn't use the return value (n1256, 6.9.1/12):

If the } that terminates a function is reached, and the value of the function call is used by the caller, the behavior is undefined.

I'm not sure whether the initial call to main should be mentioned as excluded from this general rule. It doesn't need to be: from the POV of the standard, that call doesn't have a caller, so I think that the value of the function call is not "used by the caller", even though it becomes the termination status for the program.

Steve Jessop