Hi,

Please some one clarify what does the below snippets mean and the compiler assumptions.

which one is the correct one to use, what is the problem with others.

main() 
                     {
                        
                      }
void main() 
                     {
                        
                      }
int main() 
                     {
                        
                      }
int main() 
                 {
                        
                   return 0;
                  }

Just main() means whatever the compiler accepts for it's defaults, are used. A return of int may also be the default of the compiler.

int main () with no return should give you an error "function should return a value..."

void main() is an error with the newest standards, AFAIK, but not all compilers are up to that standard, yet. Old compilers will allow it, with no errors or warnings, depending on how old a standard they are built to.

The problem with having no return, is that the OS or calling program, can't tell if the program ran without errors, or not.

int main() with a return int, is always what you want, with 0 being the default "program ran ok" value.

>which one is the correct one to use, what is the problem with others.
They're all correct in certain situations, but one is unconditionally correct:

int main(void)
{
  return 0;
}

Let's go from top down.

main() { }

This definition won't compile under C99 because implicit int was removed. C89 doesn't support an implicit return from main, so falling off the end is undefined behavior. Finally, because there's no prototype someone can call it with more than zero arguments legally:

/* Won't compile as C99: no return type */
main()
{
  main(1, 2, 3); /* OK: no prototype */
  /* Undefined behavior: no return */
}
void main() { }

This definition is undefined behavior if the compiler doesn't support void main. Lack of a prototype (the empty parameter list doesn't mean "no arguments" in C) means that main can be called with an unexpected number of arguments.

int main() { }

In C99 this definition is correct, but lack of a prototype can still cause problems with recursive calls. Note that calling main recursively is not the best practice to begin with. ;)

int main() { return 0; }

This definition is correct across the board, but the lack of a prototype issue still exists.

Comments
Thank you

I just heard from a source that some systems treat return 0 as a "function gone wrong". So to avoid platform dependencies, one should use return EXIT_SUCCESS Is this all correct?

>Is this all correct? return 0 from main means success. If the system treats 0 as an error status, the implementation must convert it to a suitable success value to be conforming.

Edited 6 Years Ago by Narue: n/a

Just to clarify it is explicitly stated in the C standard that main if returns a value of 0 (or EXIT_SUCCESS) then the program will return a value to the system that indicates the program was successful.

Note that is not necessarily 0; if the system in question does not treat 0 as success then it is the compilers or the exit codes responsibility to interpret the 0 value returned from main and return the correct value to the system.

If you return 0 from main and the system thinks your program is returning an error then you are using a non-conforming compiler and should think about changing it.

Edited 6 Years Ago by Banfa: n/a

Comments
Sounds logical to me :)

I didn't get you "the implementation must convert it..."
Since I don't know on what platform I'm working in, how would i know when to convert and when not to convert the return value?

If you return 0 from main and the system thinks your program is returning an error then you are using a non-conforming compiler and should think about changing it.

You mean to say that return 0 means, by default, success (irrespective of platform). Hurray!
So, does all this means return EXIT_SUCCESS is redundant?

The compiler must convert it...

The compiler can't possibly do that. The conversion happens at runtime, by crt0 or something else.

The compiler can't possibly do that. The conversion happens at runtime, by crt0 or something else.

Sure it can. On the proper system, when the program returns 0 to 'the system', the compiler adds exit code to the program to convert that 0 to the proper value before returning control to the system. It's code added between program code exit ( return 0; ) and actual program shutdown and system re-entrance.

You mean to say that return 0 means, by default, success (irrespective of platform). Hurray!
So, does all this means return EXIT_SUCCESS is redundant?

May be a little but good programming practices dictate that you use symbols with good semantic means rather than magic numbers.

My guess is that before standardisation EXIT_SUCCESS didn't exist and it was common to return 0 for success. At some point EXIT_SUCCESS was introduced to meet best practices of not using magic numbers but returning 0 had to be maintained as a success return for backwards compatibility.

People just continue to use 0 rather than EXIT_SUCCESS because it is rather easier to type.

Sure it can. On the proper system, when the program returns 0 to 'the system', the compiler adds exit code to the program to convert that 0 to the proper value before returning control to the system. It's code added between program code exit ( return 0; ) and actual program shutdown and system re-entrance.

Perhaps we are using a word compiler too liberally. As I said above, and you just confirmed, the conversion happens in one of the crt*.o files. These files are added by the linker. In a strict sense the compiler compiles a translation unit it into an object form - and may not (doesn't have a right to) change any observable logic. A return 0 compiles into return 0.

People just continue to use 0 rather than EXIT_SUCCESS because it is rather easier to type.

Old timers like me use 0 out of habit. I started programming before c++ was invented, and even before there was such a thing as function prototype. Magic numbers were the norm in those days -- and old habits are hard to break.

Perhaps we are using a word compiler too liberally. As I said above, and you just confirmed, the conversion happens in one of the crt*.o files. These files are added by the linker. In a strict sense the compiler compiles a translation unit it into an object form - and may not (doesn't have a right to) change any observable logic. A return 0 compiles into return 0.

And how do you think that crt0.o file got generated? It was either with the compiler or an assembler, maybe a combination of the two.

And how do you think that crt0.o file got generated? It was either with the compiler or an assembler, maybe a combination of the two.

I don't think you understand what we are talking about.

Let me rehash:
From a C standard point of view, success is signified by main returning 0. From a particular platform, a success is signified by application returning EXIT_SUCCESS, which may be different from 0. The question is, at which point a zero returned by main turns into that something different.
When one says "it is a compiler magic", it is implied that a compiler massages a return value into something else. This is what I object.
My point is that the zero returned from main is changed into platform appropriate SUCCESS at runtime, that is by the code separate from and not associated to and not adulterated by the compiler, the assembler, or any other component of a toolchain. Surely this code was compiled and assembled once.
Now what is your point?

I guess we'll just have to find a system that uses non-0 as a return and see if a return 0; actually returns 0 or the system specified SUCCESS. And if it's changed, is it during runtime or code added at compile time (which if you think about it is massaged at run time, eh?).

We may need Narue's help for a system suggestion.

You need VMS
http://www.angelfire.com/mo3/martin0/c/c_intro.html

The return 0 is important. The zero is the exit status of the program, which can be interrogated by the caller. Zero is guaranteed to indicate success in the operating system being used. On UNIX, 0 indicates success, so no change is made. On DEC VAX/VMS, success is indicated by 1 in $SEVERITY, so the zero will be translated to 1.

More here, if you're using that particular compiler...
http://www.ctrl-c.liu.se/conan?key=CRTL~exit%2C_exit&explode=yes&title=VMS+Help&referer=/

Comments
Solid posting.

In a strict sense the compiler compiles a translation unit it into an object form - and may not (doesn't have a right to) change any observable logic.

Ignoring the specific case in question this statement is wrong as a generalisation.

For instance the compiler is required to change the constant 0 when used in a pointer context into the platforms representation of the NULL pointer, which note is not required to be all bits 0.

The compiler is specificly required to change the observable logic in just the way you have claimed it has no right to.

Ignoring the specific case in question this statement is wrong as a generalisation.

For instance the compiler is required to change the constant 0 when used in a pointer context into the platforms representation of the NULL pointer, which note is not required to be all bits 0.

Strictly speaking, the standard doesn't require that; it only says that a 0 in a pointer context is guaranteed to compare unequal (6.3.2.3) etc etc. A 7.17 clause, which 6.3.2.3 refers to explains how a NULL macro shall be expanded. The standard doesn't mandate rewriting 0 in pointer context to what NULL would expand to.

The compiler is specificly required to change the observable logic in just the way you have claimed it has no right to.

Barring the debugger, how such change could be observed?

This article has been dead for over six months. Start a new discussion instead.