return statement vs exit() in main() - c++

Should I use exit() or just return statements in main()? Personally I favor the return statements because I feel it's like reading any other function and the flow control when I'm reading the code is smooth (in my opinion). And even if I want to refactor the main() function, having return seems like a better choice than exit().
Does exit() do anything special that return doesn't?

Actually, there is a difference, but it's subtle. It has more implications for C++, but the differences are important.
When I call return in main(), destructors will be called for my locally scoped objects. If I call exit(), no destructor will be called for my locally scoped objects! Re-read that. exit() does not return. That means that once I call it, there are "no backsies." Any objects that you've created in that function will not be destroyed. Often this has no implications, but sometimes it does, like closing files (surely you want all your data flushed to disk?).
Note that static objects will be cleaned up even if you call exit(). Finally note, that if you use abort(), no objects will be destroyed. That is, no global objects, no static objects and no local objects will have their destructors called.
Proceed with caution when favoring exit over return.
http://groups.google.com/group/gnu.gcc.help/msg/8348c50030cfd15a

Another difference:
exit is a Standard Library
function so you need to include
headers and link with the standard
library. To illustrate (in C++),
this is a valid program:
int main() { return 0; }
but to use exit you'll need an include:
#include <stdlib.h>
int main() { exit(EXIT_SUCCESS); }
Plus this adds an additional assumption: that calling exit from main has the same side effects as returning zero. As others have pointed out, this depends on what kind of executable you're building (i.e., who's calling main). Are you coding an app that uses the C-runtime? A Maya plugin? A Windows service? A driver? Each case will require research to see if exit is equivalent to return. IMHO using exit when you really mean return just makes the code more confusing. OTOH, if you really do mean exit, then by all means use it.

There is at least one reason to prefer exit: If any of your atexit handlers refer to automatic-storage-duration data in main, or if you used setvbuf or setbuf to assign to one of the standard streams an automatic-storage-duration buffer in main, then returning from main produces undefined behavior, but calling exit is valid.
Another potential usage (usually reserved for toy programs, however) is to exit from a program with recursive invocations of main.

I always use return because the standard prototype for main() says that it does return an int.
That said, some versions of the standards give main special treatment and assume that it returns 0 if there's no explicit return statement. Given the following code:
int foo() {}
int main(int argc, char *argv[]) {}
G++ only generates a warning for foo() and ignores the missing return from main:
% g++ -Wall -c foo.cc
foo.cc: In function ‘int foo()’:
foo.cc:1: warning: control reaches end of non-void function

I STRONGLY second the comment by R. about using exit() in order to avoid having automatic storage in main() reclaimed before the program actually ends. A return X; statement in main() is not precisely equivalent to a call to exit(X);, since the dynamic storage of main() vanishes when main() returns, but it it does not vanish if a call to exit() is made instead.
Furthermore, in C or any C-like language a return statement strongly hints to the reader that execution will continue in the calling function, and while this continuation of execution is usually technically true if you count the C startup routine which called your main() function, it's not exactly what you mean when you mean to end the process.
After all, if you want to end your program from within any other function except main() you must call exit(). Doing so consistently in main() as well makes your code much more readable, and it also makes it much easier for anyone to re-factor your code; i.e. code copied from main() to some other function won't misbehave because of accidental return statements that should have been exit() calls.
So, combining all of these points together the conclusion is that it's a bad habit, at least for C, to use a return statement to end the program in main().

Does exit() do anything special that 'return' doesn't?
With some compilers for uncommon platforms, exit() might translate its argument into your program's exit value while a return from main() might just pass the value directly to the host environment without any translation.
The standard requires identical behavior in these cases (specifically, it says returning something that's int-compatible from main() should be equivalent to calling exit() with that value). The problem is that different OSes have different conventions for interpreting the exit values. On many (MANY!) systems, 0 means success and anything else is a failure. But on, say, VMS, odd values mean success and even ones mean failure. If you returned 0 from main(), a VMS user would see a nasty message about an access violation. There wasn't actually an access violation--that was simply the standard message associated with failure code 0.
Then ANSI came along and blessed EXIT_SUCCESS and EXIT_FAILURE as arguments you could pass to exit(). The standard also says that exit(0) should behave identically to exit(EXIT_SUCCESS), so most implementations define EXIT_SUCCESS to 0.
The standard, therefore, puts you in a bind on VMS, as it leaves no standard way to return a failure code that happens to have the value 0.
The early-1990s era VAX/VMS C compiler therefore did not interpret the return value from main(), it simply returned whatever value to the host environment. But if you used exit() it would do what the standard required: translate EXIT_SUCCESS (or 0) into a success code and EXIT_FAILURE into a generic failure code. To use EXIT_SUCCESS, you had to pass it to exit(), you could not return it from main(). I don't know whether more modern versions of that compiler preserved that behavior.
A portable C program used to look like this:
#include <stdio.h>
#include <stdlib.h>
int main() {
printf("Hello, World!\n");
exit(EXIT_SUCCESS); /* to get good return value to OS */
/*NOTREACHED*/ /* to silence lint warning */
return 0; /* to silence compiler warning */
}
Aside: If I recall correctly, the VMS convention for exit values is more nuanced than odd/even. It actually uses something like the low three bits to encode a severity level. Generally speaking, however, the odd severity levels indicated success or miscellaneous information and the even ones indicated errors.

In C returning from main is exactly the same as calling exit with the same value.
Section 5.1.2.2.3 of the C standard states:
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; 11) 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.
The rules for C++ are a bit different as mentioned in other answers.

There actually IS a difference between exit(0) and return(0) in main – when your main function is called multiple times.
The following program
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {
if (argc == 0)
return(0);
printf("%d", main(argc - 1, argv));
}
Run as
./program 0 0 0 0
Will result in following output:
00000
However this one:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {
if (argc == 0)
exit(0);
printf("%d", main(argc - 1, argv));
}
Won't print anything regardless of the arguments.
If you are sure that nobody will ever call your main explicitly it is not technically a big difference in general, but to maintain clearer code exit would look much better. If you for some reason want to call main – you should adjust it to your needs.
Speaking about C.

Related

Is longjmp supposed to restore the stack?

From what I understood, setjmp saves the current context and it's supposed to restore it when calling longjmp. However the next piece of code prints 15 (I compiled with -g and without any optimization). Did I misunderstand this construct or am I missing anything else?
#include <iostream>
#include <csetjmp>
std::jmp_buf jump_buffer;
int main()
{
int a = 0;
if (setjmp(jump_buffer) == 0) {
a = 15;
std::longjmp(jump_buffer, 42);
}
std::cerr << a << std::endl;
}
Disclaimer: only trying to use it for curiosity. I never heard about this construct until I recently read some paper about NASA coding guidelines that mentioned it's forbidden to use this flow of control construct
Using both c and c++ tags because the code is mixed and I would assume the actual relevant functions are more relevant to c heavy users rather than c++... :/
That's the expected behavior:
Upon return to the scope of setjmp, all accessible objects,
floating-point status flags, and other components of the abstract
machine have the same values as they had when std::longjmp was
executed, except for the non-volatile local variables in setjmp's
scope, whose values are indeterminate if they have been changed since
the setjmp invocation.
The value of a when executing longjmp is 15, so that is a value one could expect to see (it's indeterminate in general). The jmp_buf only stores the point of execution. Not the state of every variable in the program.
The except for the non-volatile local variables in setjmp's scope, whose values are indeterminate if they have been changed since the setjmp invocation. part of the description is really important, because the value you're seeing falls into that indeterminate category.
Consider a slight modification to your program:
#include <iostream>
#include <csetjmp>
std::jmp_buf jump_buffer;
void func() {
std::longjmp(jump_buffer, 42);
}
int main()
{
int a = 0;
volatile int b = 0;
if (std::setjmp(jump_buffer) == 0) {
a = 15;
b = 1;
func();
}
std::cout << a << ' ' << b << '\n';
}
When I compile and run this version (With -O), I get 0 1 as output, not 15 1 (Because a is indeterminate, your results may vary).
If you want a local variable that's changed between the initial setjmp() call and calling longjmp() to reliably keep that change, it needs to be volatile.
For setjmp and longjmp the "context" is the execution context, not the actual contents of the stack (where local variables are commonly stored).
Using setjmp and longjmp you can't "roll back" changes made to local variables.
I think you might be seeing older codebase. Where exception was not quite popular or not available in some compilers.
You should not use setjmp & longjmp until you are working more close to system software.
As for the control flow: setjmp returns twice, and longjmp never
returns.
When you call setjmp for the first time, to store the
environment, it returns zero,
And then when you call longjmp, the control flow passes to return from setjmp with the value provided in the argument.
Use cases are generally cited as “error handling”, and
“don’t use these functions”.
setjmp & longjmp stores & restore the CPU SFRs(i.e. context registers).
Here’s a little control flow example:
#include <stdio.h>
#include <setjmp.h>
jmp_buf env;
void foo()
{
longjmp(&env, 10); +---->----+
} | |
| |
int main() (entry)---+ ^ V
{ | | |
if(setjmp(&env) == 0) | (= 0) | | (= 10)
{ | ^ |
foo(); +---->----+ |
} +---->----+
else |
{ |
return 0; +--- (end)
}
}
“Setjump” and “Longjump” are defined in setjmp.h, a header file in C standard library.
setjump(jmp_buf buf) : uses buf to remember current position and returns 0.
longjump(jmp_buf buf, i) : Go back to place buf is pointing to and return i .
Simple Example
#include <stdio.h>
#include <setjmp.h>
static jmp_buf buf;
void second() {
printf("second\n"); // prints
longjmp(buf,1); // jumps back to where setjmp was called - making setjmp now return 1
}
void first() {
second();
printf("first\n"); // does not print
}
int main() {
if (!setjmp(buf))
first(); // when executed, setjmp returned 0
else // when longjmp jumps back, setjmp returns 1
printf("main\n"); // prints
return 0;
}
This is the reason why setjump() returns 0 for you and as you check for condition,it assigns a=15 and once the process is done,next step it would give 42.
The main feature of these function is to provide a way that deviates from standard call and return sequence. This is mainly used to implement exception handling in C. setjmp can be used like try (in languages like C++ and Java). The call to longjmp can be used like throw (Note that longjmp() transfers control to the point set by setjmp()).
I'd just like to answer the other part of the question, by speculating why NASA would forbid these functions (basically linking relevant answers from SO). The use of setjmp and longjmp are discouraged in C++ more so than in C code, due to undefined behavior regarding automatic object destruction, see this SO thread, particularly the comments to the accepted answer:
Generally, whenever there's some way to exit a scope in C++ (return, throw, or whatever), the compiler will place instructions to call the dtors for any automatic variables that need to be destroyed as a result of leaving that block. longjmp() just jumps to a new location in the code, so it will not provide any chance for the dtors to be called. The standard is actually less specific than that - the standard doesn't say that dtors won't be called - it says that all bets are off. You can't depend on any particular behavior in this case.
[...]
Since smart pointers depend on being destroyed, you will get undefined behavior. It's likely that that undefined behavior would include a refcount not getting decremented. You're 'safe' using longjmp() as long as you don't longjmp out of code that should cause dtors to be invoked. However, as David Thornley noted in a comment, setjmp()/longjmp() can be tricky to use right even in straight C - in C++ they're downright dangerous. Avoid them if at all possible.
So what makes the setjmp()/longjmp() tricky in C? Look at possible use cases we can see that one of them is implementation of coroutines. The answer was already given here in the comments #StoryTeler, but could you use goto across different functions?
You can't in Standard C; labels are local to a single function.
The nearest standard equivalent is the setjmp() and longjmp() pair of functions.
However, you're quite limited with setjmp and longjmp as well, and you might quickly run into a segfault. The treasure can again be found in the comments:
You can think of a longjmp() as an "extended return". A successful longjmp() works like a series of successive returns, unwinding the call stack until it reaches the corresponding setjmp(). Once the call stack frames are unwound, they are no longer valid. This is in contrast to implementations of coroutines (eg. Modula-2) or continuations (eg. Scheme) where the call stack remains valid after jumping somewhere else. C and C++ only support a single linear call stack, unless you use threads where you create multiple independent call stacks.

Better alternatives to assert(false) in C/C++

Currently, I write
assert(false);
at places that my code is never supposed to reach. One example, in a very C-ish style, is:
int findzero( int length, int * array ) {
for( int i = 0; i < length; i++ )
if( array[i] == 0 )
return i;
assert(false);
}
My compiler recognizes that the program finishes once assert(false) has been reached. However, whenever I compile with -DNDEBUG for performance reasons, the last assertion vanishes and the compiler warns that the execution finishes the function without a return statement.
What are better alternatives of finishing off a program if a supposedly unreachable part of the code has been reached? The solution should
be recognized by the compiler and not produce warnings (like the ones above or others)
perhaps even allow for a custom error message.
I am explicitly interested in solutions no matter whether it's modern C++ or like 90s C.
Replacing your assert(false) is exactly what "unreachable" built-ins are for.
They are a semantic equivalent to your use of assert(false). In fact, VS's is spelt very similarly.
GCC/Clang/Intel:
__builtin_unreachable()
MSVS:
__assume(false)
These have effect regardless of NDEBUG (unlike assert) or optimisation levels.
Your compiler, particularly with the above built-ins but also possibly with your assert(false), nods its head in understanding that you're promising that part of the function will never be reached. It can use this to perform some optimisations on certain code paths, and it will silence warnings about missing returns because you've already promised that it was deliberate.
The trade-off is that the statement itself has undefined behaviour (much like going forth and flowing off the end of the function was already). In some situations, you may instead wish to consider throwing an exception (or returning some "error code" value instead), or calling std::abort() (in C++) if you want to just terminate the program.
There's a proposal (P0627R0), to add this to C++ as a standard attribute.
From the GCC docs on Builtins:
If control flow reaches the point of the __builtin_unreachable, the program is undefined. It is useful in situations where the compiler cannot deduce the unreachability of the code. [..]
I like to use
assert(!"This should never happen.");
...which can also be used with a condition, as in
assert(!vector.empty() || !"Cannot take element from empty container." );
What's nice about this is that the string shows up in the error message in case an assertion does not hold.
As a fully portable solution, consider this:
[[ noreturn ]] void unreachable(std::string_view msg = "<No Message>") {
std::cerr << "Unreachable code reached. Message: " << msg << std::endl;
std::abort();
}
The message part is, of course, optional.
Looks like std::unreachable() made it to C++23:
https://en.cppreference.com/w/cpp/utility/unreachable
I use a custom assert that turns into __builtin_unreachable() or *(char*)0=0 when NDEBUG is on (I also use an enum variable instead of a macro so that I can easily set NDEBUG per scope).
In pseudocode, it's something like:
#define my_assert(X) do{ \
if(!(X)){ \
if (my_ndebug) MY_UNREACHABLE(); \
else my_assert_fail(__FILE__,__LINE__,#X); \
} \
}while(0)
The __builtin_unreachable() should eliminate the warning and help with optimization at the same time, but in debug mode, it's better to have an assert or an abort(); there so you get a reliable panic. (__builtin_unreachable() just gives you undefined behavior when reached).
I recommend C++ Core Gudelines's Expects and Ensures. They can be configured to abort (default), throw, or do nothing on violation.
To suppress compiler warnings on unreachable branches you can also use GSL_ASSUME.
#include <gsl/gsl>
int findzero( int length, int * array ) {
Expects(length >= 0);
Expects(array != nullptr);
for( int i = 0; i < length; i++ )
if( array[i] == 0 )
return i;
Expects(false);
// or
// GSL_ASSUME(false);
}
assert is meant for scenarios that are ACTUALLY supposed to be impossible to happen during execution. It is useful in debugging to point out "Hey, turns out what you thought to be impossible is, in fact, not impossible." It looks like what you should be doing in the given example is expressing the function's failure, perhaps by returning -1 as that would not be a valid index. In some instances, it might be useful to set errno to clarify the exact nature of an error. Then, with this information, the calling function can decide how to handle such error.
Depending on how critical this error is to the rest of the application, you might try to recover from it, or you might just log the error and call exit to put it out of its misery.
I believe the reason you are getting the errors is because assertions are generally used for debugging on your own code. When these functions are run in release, exceptions should be used instead with an exit by std::abort() to indicate abnormal program termination.
If you still want to use asserts, there is an answer about defining a custom one by PSkocik, as well as a link here where someone proposes the use of custom asserts and how to enable them in cmake here as well.
One rule that is sometimes found in style-guides is
"Never return from the middle of a function"
All functions should have a single return, at the end of the function.
Following this rule, your code would look like:
int findzero( int length, int * array ) {
int i;
for( i = 0; i < length; i++ )
{
if( array[i] == 0 )
break; // Break the loop now that i is the correct value
}
assert(i < length); // Assert that a valid index was found.
return i; // Return the value found, or "length" if not found!
}

How does main() handle a variable number of arguments without ellipses? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 8 years ago.
Improve this question
How does the main() function handle a variable number of arguments without the use of ellipses (...)? For processing variable number of arguments, last argument to the function should be ... which is not the case with the main() function.
Basically, main() is special, and it has two standard-defined forms:
int main(int argc, char **argv)
int main(void)
The system may support other forms; it is common that the environment is also made available:
int main(int argc, char **argv, char **envp)
These forms are fixed. The only unusual thing is that a system must support either of the first two (and some systems support others as well).
The variable number of command line arguments is handled via an array of pointers to strings (that's argv above), unlike say execl() from POSIX.
See also:
How does the main() function in C work?
What should main() return in C and C++?
rahul manglani commented:
The two links you mentioned made it pretty clear. There are different possible approaches listed there, which of them is actually being used is not mentioned.
In a sense, it doesn't matter; the system simply has to work, and the people who produce 'the system' must make it work. You as the programmer using the system don't need to know how it works; you can simply assume that it does work.
Behind the scenes, what usually happens is that the 'start' function which calls main() does some fixup work (in the case of a C++ program in particular, a lot of fixup work — such as ensuring all the constructors that must be executed before main() starts are in fact executed), but ends with a fixed sequence such as:
exit(main(argc, argv, environ));
Note that environ is a global variable, extern char **environ; (which is unique among the global variables defined by POSIX in that no header declares it) and it contains the pointers to the environment variables. The 'start' code has to ensure that is set; it is trivial to pass environ as an argument to main(), therefore.
This calls main() with a fixed argument list and calls exit() if/when it returns. Indeed, Apple takes it a step further and passes a fourth argument to main(). If the called function was defined as int main(void) { … }, it simply ignores the arguments it was passed; if it was defined as int main(int argc, char **argv) { … }, it can access the command line arguments as usual; if it was defined as int main(int argc, char **argv, char **envp) { … }, then it can access the environment too.
Generally, the systems are set up so that extra arguments don't cause damage. This is a reason why C is unusual in its calling conventions and it's why the called function doesn't clean up the arguments pushed onto the stack — the called function doesn't know how many arguments were actually pushed onto the stack. It assumes that the ones it expects were provided and uses those without problems, but the calling code knows what it pushed so it can clean up properly. The biggest problems occur if the called function expects N arguments but the caller passes M arguments and M < N. (There are also issues of types pushed and the sizes of those types, etc, but that's a second-order problem.)
In C/C++ main takes 2 parameters, typically called argc, and argv. The argv parameter is an array of argc char arrays. Command line arguments are passed to the program in argv. There are variations on this theme with the exact number of parameters, but main's signature is generally
int main(int argc, char **argv);
I interpreted this question to mean: how is it possible that main can take either zero arguments or two arguments?
While the details are obviously implementation-dependent, on most implementations, the default C calling convention is that the caller cleans the stack. Therefore, the code that calls main is at perfect liberty to always push two arguments onto the stack (argc and argv), whatever the declaration of main might be. If main is declared with no arguments, then main simply won't access the values of the arguments it receives. After main returns, the calling code clears the stack.
It should be pointed out that main isn't even special in this sense. Try this:
int printf();
int main() { printf("Hello, world!\n"); }
The C compiler will happily allow you to call printf even though, lacking an #include <stdio.h> directive, it has no idea how many arguments printf actually wants. Presumably, the code that calls main is conceptually something like this:
int main(int argc, char** argv); /* declare "main" */
main(argc, argv); /* call "main" */
If the definition of main actually specifies zero parameters, this still works (although I believe it would technically be undefined behaviour if you actually did this).
In the case of C++, although the linkage of main is left unspecified by the standard, most implementations simply treat it as though it has C linkage, so the name is not mangled and everything above still applies.
It handles it by accepting an array and array length set as variables argc and argv
you may find more data here:
http://crasseux.com/books/ctutorial/argc-and-argv.html

Does C++ return 0 or NULL on failure?

What's the value of return when a C++ program fails? I've read some articles on this but nothing explicit.
If it doesn't return 0, is there a way into making the program return 0 or NULL on failure? I've red something about std::nothrow but found no practical examples so far. Can anyone clarify this to me?
The standard defines EXIT_SUCCESS and EXIT_FAILURE error codes with obvious meanings. They can be passed to either exit() function or explicitly returned with return statement from the main function. You can wrap the whole main function like
int main() try {
...
} catch(...) {
return EXIT_SUCCESS;
}
Your question is otherwise unclear.
NULL is just a macro for 0 as far as I know.
In stdlib.h:
/* Define NULL pointer value */
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
The source (German) where I copied this from also states that using NULL is not recommended by Stroustrup.
The question is a bit unclear. The value that you return from main is precisely the value that you pass to the return statement in main. Nothing else can be said about that.
Now, what question should you really be asking? There are two aspects: One is the C++ side, and the other is the host side (i.e. the operating system).
You don't have any control over how any given operating system handles error conditions of programs that it launches. The only thing that the C++ standard guarantees are this:
If your main returns 0, EXIT_SUCCESS, or not at all, then the program ends in a manner that signals success; and
if your main returns EXIT_FAILURE, then the program ends in a manner that signals failure.
The actual return values of your program depend entirely on the platform, i.e. the operating system and the runtime environment.
For example, on Linux success is signalled via the value 0 and failure via a non-zero value, so a C or C++ program can be executed by simply returning the value of main() back to the OS (and defining EXIT_SUCCESS as 0). Other platforms may choose different semantics!
There is commonly assumed that a program returns 0 when it succeeds, and non-zero value otherwise.
You set the return value by returning from main function:
int main(int argc, char ** argv){
return 0; // Finish with success
}
or by passing the return code to the exit(int) function.
Also it is worth noting, that NULL is defined precisely as (void*)0 and is used when talking about pointers, not integers. If you don't understand what does it mean, read a decent C tutorial.
NULL is macro and it is same sa 0, it's defined like so:
#define NULL 0
when program fails it return 1 by default signaling the operating system that program failed.
if return value is grater than 1 then this is done by programer who wroted that program.
if program executes sucessefuly it always retun's 0.
you should never retun value other than 0 on program failure cos you will not know if it failed or not.
also if return value is lower thatn 0 that means fail as well.
so only sucess value is 0 or NULL which is same.
Successful runs usually have error code 0, anything other than 0 indicates some sort of error.
Error code Value Description
ERROR_SUCCESS 0 The action completed successfully.
ERROR_INVALID_DATA 13 The data is invalid.
ERROR_INVALID_PARAMETER 87 One of the parameters was invalid.
More : http://msdn.microsoft.com/en-us/library/windows/desktop/aa368542(v=vs.85).aspx

Why do we need to use `int main` and not `void main` in C++? [duplicate]

This question already has answers here:
What should main() return in C and C++?
(19 answers)
Closed 7 years ago.
Why do we need to use int main and not void main in C++?
The short answer, is because the C++ standard requires main() to return int.
As you probably know, the return value from the main() function is used by the runtime library as the exit code for the process. Both Unix and Win32 support the concept of a (small) integer returned from a process after it has finished. Returning a value from main() provides one way for the programmer to specify this value.
Most Operating Systems report back to the user, or the calling process, if an application was successful or not. This is especially useful in scripting, where the script can conditionally branch (if-then) on the results of a program. Something along the lines of:
// pseudo-code
screenscrape http://mydatasource.com > results.txt
if errorlevel == 0 then
processfile results.txt
else
echo Screen Scraping Failed!
end if
This result status is done via the return value of main.
While some compilers allow for void main, for the sake of consistency and simplicity, the ANSI standard requires one single prototype of main:
int main(int argc, char *argv[]);
Because in C, arguments are cleaned up by the caller, the author of main can neglect to declare or process the arguments argc & argv. However, if the setup-routines that call main expect an int return value, and instead don't find one, behavior can undefined.
Short answer:
The return value of main is useful
for scripting.
The setup and cleanup routines that invoke main need a consistent interface to use.
Main reason for changing
void main() { }
to
int main() { }
in later releases was to notify error occurred in program during execution to operating system on which it running
return 0;
identify program successfully executed if any number rather then 0 returned that means some error occurred who's error code is which returned by main.
if you are running on codeblock IDE see in build log if main return 0 it normally display
Process terminated with status 0
else it display status code in red which means an error occurred
From Wikipedia:
The value returned from the main function becomes the exit status of the process, though the C standard only ascribes specific meaning to two values: EXIT_SUCCESS (traditionally zero) and EXIT_FAILURE. The meaning of other possible return values is implementation-defined.
As in C, because the process will give the OS an exit code.
You can either use
int main (int argc, char ** argv)
{
return (0);
}
or
int main (int argc, char ** argv)
{
exit (0);
}
This is at least in C89 IIRC.
Because int is the returncode a program can return to the OS.
You can query this value to check if operation has been succesfull.
This was extremely helpfull when using commandline scripts.
When we execute our program to check it runs successfully or not. So when it returns 0 that means it's true & ran successfully, if it returns 1 then it's not run successfully & this int value tells the OS if the program ran successfully or not
Perhaps because it makes sense to cleanly exit with a status code from the main() method. In Java, we have to emulate this using System.exit() which is not all that graceful.