Non-standard signature of main() compiles successfully - c

In this code:
int main(int a, int b)
{
printf(" main(int, int) works \n\n");
return 0;
}
the signature of main is main(int, int), and it compiles successfully. Why?

Because the C standard doesn't prohibit non-standard signatures for main (see e.g. section 5.1.2 of the C99 standard).
However, you'll find that if you compile under GCC with the -Wall flag,1 it will complain:
test.c:4: warning: second argument of 'main' should be 'char **'
It assumes that you want to interact with a standard environment (i.e. process command-line parameters and return an exit status), in which case you must use int main(int, char **) or int main(void). If you use anything else, the contents of the arguments will be undefined.
1. I really wish ideone.com would allow you to specify compiler flags!

The C standard specifically prohibits the implementation from providing a prototype for main (C99, §5.1.2.2.1/1: "The function called at program startup is named main. The implementation declares no prototype for this function."), and a mismatch from the prototype is what would (normally) stop the code from compiling.
Without a prototype, you're back to programming like in the bad old days, when it was up to you to ensure that the arguments you passed to a function matched what it expected. Thankfully in the case of main, the signature is so well known that it's rarely a problem though.
Edit: note that if you want to badly enough, it's actually even possible to make use of the version with two int parameters (though the technique is prohibited in C++). main can call itself recursively, and in such a case can/could pass two int parameters:
int main(int a, int b) {
if (a == 2)
main(2, 10);
printf("%d, %d", a, b);
return 0;
}
This is pretty useless as it stands, but gives the general idea -- you're expected to run the program with no command line arguments, in which case a (which will receive what you normally call argc) will normally be 1 (i.e., the only argument it's trying to pass is the name of the program in argv[0]). In this case, it calls itself with some other values. When that happens, it prints out those values.
To be fair, I should add that that's pretty close to purely theoretical, and certainly not recommended. It'll work with most typical implementations, but the standard doesn't guarantee it. It's a silly, roundabout way to accomplishing what it does -- but at least with most typical compilers, it is (just barely) possible anyway.

There is no header file that specifies the signature of main, so no error will be reported. The compiler usually checks the return value only, for the case of main (the warnings of the signature of main is compiler dependent).

int main(int a, int b)
this is meaningless as the arguments passed to the main function are always
int main(int argc,char *argv[])
main is an unusual function.It is called by the operating system, and as C++ can run on many systems and the C++ standards cannot dictate to OS writers what data they pass to programs running on that OS - you can write any parameters you like in the main functions and the compiler will accept it.

Related

Why there is no error when passing command line arguments when declaring main as `int main(void)`?

Case 1:
void hello(void) {
//something
}
int main()
{
hello(1); //error
return 0;
}
Case 2:
int main(void) {
//something
return 0;
}
Execution:
./a.out something something //No error, Why?
Why there is no error? main will not be able to take any arguments. So why it is possible to provide arguments from the command line?
Because the C compiler and the command line interpreter (or whatever is used to invoke your program) are different things.
The C language allows various ways how main () could be declared.
The command line interpreter will make any arguments available to the program. If the program ignores them, that's none of its business.
The command line interpreter doesn't even know that you used C to compile your program. On my computer, the program could be written in C, C++, Objective-C, Objective-C++, Swift, Fortran, Ada, and so on. Each of these compilers may or may not do things to accept commands from the command line.
Not checking the specification nor compiled result, it will cause no error because the C runtime will get the arguments and pass them to main(), but this type of main() will ignore the passed arguments, and if it is caller's duty to clean up the memory (stack) used as the arguments, it will cause no problems just as getting some arguments and not using them in the code.
This code won't emit errors in C:
void hello(); // in C, the compiler won't check arguments
int main() {
hello(1); //no error
return 0;
}
void hello(void) {
//something
}
Because ./a.out something something is not directly calling your main function. THe main function is being called by the c runtime library. The command line arguments are placed in a region somewhere on the stack (very beginning) by the loader/c runtime. It is upto you if you want to access these arguments or not.
Plus as pointed out in one of the comments as well at least one command line argument is always passed anyways (the name of the program ./a.out to be precise) - so you must have wondered about an error in that case as well.
Recall that ISO C specifies the two possible signatures of main: int main(void) and int main(int, char *[]) and the equivalent versions thereof, like int main(int, char **) because of array-to-pointer decay. This is covered more in detail here.
This question can be answered by considering the opposite question: how does the C runtime know what main to call? C doesn't have overload resolution! This is explained here. Briefly, the others are pushed but not accessed because there's no indication from C to do that.
When you compile your program using gcc program_name.c, compiler will report any possible compile time warning or error. Since the command line arguments are not passed at the compile time, compiler is unaware of it and program just ignore that arguments.
In case of hello, compiler knows the prototype of this function and expects no argument to be passed in its call and hence reports error in case of any argument passed to it.

How is an invalid return type of main() handled by the OS?

I started programming with following definition of main()
void main(){}
Then somebody told me that this format of main() is bad programming because it should return int. He also told me that following definitions of main() are valid in C.
int main(void){}
or
int main(int argc,int *argv[]){}
Today I tried to experiment with other data types and surprisingly all the following compiles without errors.
char main(){}
float main(){}
int* main(){}
and even this compiles successfully
struct Abc{
int a;
};
struct Abc* main(){}
So my questions regarding this are following:
How does the OS deal with these unexpected return types? [I am asking this because I think return value of main() is used by OS]
Why is main() allowed to return any type?
Why do compiler designers make this so flexible by saying "main() should return int" I think there would be no problem if they said "main() must return int"?
If the return type of main is not either int or some implementation-defined type (where "implementation-defined" means that it's documented by the implementation), the behavior is undefined.
That means that a compiler is not required to issue a warning or error message, but the C standard says nothing about how the program behaves.
The actual behavior depends on the compiler (calling conventions, etc.) and on the operating system.
In many cases, the value returned by main (if any) will simply be interpreted as if it were an int. If it returns a double with the value 1.0, it might be equivalent to returning an int value 1065353216.
Or the compiler might reject it at compile time. Or your program might crash. As far as the C standard is concerned, literally anything can happen.
There are a lot of coding errors in C that compilers are not required to detect or to handle in any particular way. In such cases, it's entirely up to the programmer to get things right.
Just use the correct declaration. For hosted implementations, use either
int main(void) { /* ... */ }
or
int main(int argc, char *argv[]) { /* ... */ }
(For freestanding (embedded) implementations, the declaration is entirely implementation-defined, and the entry point may or may not be called main; consult your compiler's documentation.)
As for why declaring main incorrectly doesn't require a diagnostic, I'm not entirely sure. It does make things slightly simpler for compiler writers. They can treat main just like any other function. There are some non-standard forms that are actually useful; for example, UNIX-like systems sometimes permit
int main(int argc, char *argv[], char *envp) { /* ... */ }
where the third argument provides access to environment variables. I personally would prefer it if incorrect definitions of main had to be diagnosed.
This is also discussed in the comp.lang.c FAQ, starting at question 11.12a.
The OS expects return value of type int and gets it from the default place (e.g. register EAX). If you return other type, the OS will get value of EAX again. Nothing special.

What are the differences between: main(){}, int main(){} and int main(void){} [duplicate]

This question already has answers here:
What should main() return in C and C++?
(19 answers)
Why is the type of the main function in C and c++ left to the user to define? [duplicate]
(6 answers)
Closed 9 years ago.
I am currently learning C and I have written many small programs. However, I have noticed that the main function could start as
main()
{
//code
}
or
int main()
{
//code
return 0;
}
or
int main(void)
{
//code
return 0;
}
Which option should I use? Thanks!
For Standard C
For a hosted environment (that's the normal one), the C99 standard
says:
5.1.2.2.1 Program startup
The function called at program startup is named main. The implementation declares no prototype for this function. It shall be
defined with a return type of int and with no parameters:
int main(void) { /* ... */ }
or with two parameters (referred to here as argc and argv, though any names may be used, as they are local to the function in which they
are declared):
int main(int argc, char *argv[]) { /* ... */ }
or equivalent;9) or in some other implementation-defined manner.
9) Thus, int can be replaced by a typedef name defined as int, or the type of argv can be written as char **argv, and
so on.
This (is valid in C89) main() implicitly meant (previously) int main(void). However the default return type rule has been abandoned in C99. Also:
main() means - a function main taking an unspecified number of arguments of.
main(void) means "a function main taking no arguments.
Your first example uses a feature inherited from the outdated dialect of C which predated the first ANSI(1989) and ISO(1990) standard: namely, that you can write a function which doesn't specify its return type, and in that case the type defaults to int.
In early C, the void keyword and associated type did not exist. When programmers wanted to write procedures ("functions that have a side effect, but do not return anything"), they simulated it using this feature. They wrote a function without any keyword specifying the return type. They allowed the function to execute to it last statement without returning a value (or alternatively, they used return; to exit from the middle without supplying a value), and they wrote the calls to the function such that those calls did not try to use the return value:
parse_input() /* similar to a procedure in Pascal, but fake! */
{
/* ... */
if (condition())
return; /* no value */
/* ... */
/* fall off end here */
}
int main()
{
parse_input(); /* no return value extracted, everything cool! */
return 0;
}
Unfortunately, some programmers also started not caring about the termination status of a program and writing main itself in this procedure style:
main()
{
/* do something */
/* fall off the end without returning a value */
}
(A mixed style also existed: omitting the int declarator but returning an integer value.)
These programs failing to return a value had an indeterminate termination status. To the operating system, their execution could look successful or failed. Woe to the script writer who tried to depend on the termination status of such a program!
Then things took a turn for the worse. C++ came along and introduced void, and it was adopted into C. With the void keyword in C++, one could declare a function that actually returns nothing (and make it an error to have a return; statement in any other kind of function). The dummy programmers who used to write main with no return type got dumber, and started sticking this new-fangled, fresh-out-of-C++ void in front:
void main() /* yikes! */
{
/* do something */
/* fall off the end without returning a value */
}
By this time they had forgotten that when they wrote main(), it actually meant int main(), which made the function have a compatible type with the startup call invoked by the environment (except for the matter of neglecting to return a value). Now they actually had a different function type from the expected one, which might not even be successfully called!
Where things stand now is that in C++ and in the latest C++ standard, main is still required to return an int. But both languages make a concession for the original dummy programmers: you can let execution "fall off" the end of main and the behavior is as if return 0; had been executed there. So this trivial program now has a successful termination status as of C99 and, I think, C++98 (or possibly earlier):
int main()
{
}
But neither language makes a concession for the second-generation dumber programmers (and everyone else who read the C books that those programmers wrote in the 1980's and since). That is, void is not a valid return declarator for main (except where it is documented by platforms as being accepted, and that applies to those platforms only, not to the portable language).
Oh, and allowance for the missing declarator was removed from C in C99, so main() { } is no longer correct in new dialects of C, and isn't valid C++. Incidentally, C++ does have such a syntax elsewhere: namely, class constructors and destructors are required not to have a return type specifier.
Okay, now about () versus (void). Recall that C++ introduced void. Furthermore, though C++ introduced void, it did not introduce the (void) argument syntax. C++ being more rigidly typed introduced prototype declarations, and banished the concept of an unprototyped function. C++ changed the meaning of the () C syntax to give it the power to declare. In C++, int func(); declares a function with no arguments, whereas in C, int func(); doesn't do such a thing: it declares a function about which we do not know the argument information. When C adopted void, the committee had an ugly idea: why don't we use the syntax (void) to declare a function with no arguments and then the () syntax can stay backward compatible with the loosey-goosey legacy behavior pandering to typeless programming.
You can guess what happened next: the C++ people looked at this (void) hack, threw up their arms and copied it into C++ for the sake of cross-language compatibility. Which in hindsight is amazing when you look at how the languages have diverged today and basically no longer care about compatibility to that extent. So (void) unambiguosly means "declare as having no arguments", in both C and C++. But using it in C++ code that is obviously pure C++ never intended to be C is ugly, and poor style: for instance, on class member functions! It doesn't make much sense to write things like class Foo { public: Foo(void); virtual ~Foo(void) /*...*/ };
Of course, when you define a function like int main() { ... }, the function which is defined has no arguments, regardless of which language it is in. The difference is in what declaration info is introduced into the scope. In C we can have the absurd situation that a function can be fully defined, and yet not declared, in the same unit of program text!
When we write main, usually it is not called from within the program, and so it doesn't matter what the definition declares. (In C++, main must not be called from the program; in C it can be). So it is immaterial whether you write int main() or int main(void), regardless of whether you're using C or C++. The thing which calls main does not see any declaration of it (that you write in your program, anyway).
So just keep in mind that if you write:
int main() /* rather than main(void) */
{
}
then although it is perfect C++ and correct C, as C it has a slight stylistic blemish: you're writing an old-style pre-ANSI-C function that doesn't serve as a prototype. Though it doesn't functionally matter in the case of main, you may get a warning if you use some compilers in a certain way. For instance, GCC, with the -Wstrict-prototypes option:
test.c:1:5: warning: function declaration isn’t a prototype [-Wstrict-prototypes]
Because -Wstrict-prototypes is a darn useful warning to turn on when programming in C, for improved type safety, (along with -Wmissing-prototypes), and we strive to eliminate warnings from our compile jobs, it behooves us to write:
int main(void) /* modern C definition which prototypes the function */
{
}
which will make that diagnostic go away.
If you want main to accept arguments, then it is int main(int argc, char **argv) where the parameter names are up to you.
In C++, you can omit parameter names, so this definition is possible, which serves nicely in the place of main().
int main(int, char **) // both arguments ignored: C++ only
{
}
Since the argument vector is null-pointer-terminated, you don't need argc, and C++ lets us express that without introducing an unused variable:
#include <cstdio>
int main(int, char **argv) // omitted param name: C++ only
{
// dump the arguments
while (*argv)
std::puts(*argv++);
}
first :
declares a function main - with no input parameters. Although main should have returns ( your compiler will take care of this )
2nd/3rd:
Declare a function main which returns an int and takes in no input parameters
You should use 3rd format. Rather this is the best way:
int main(int argc, char *argv[]){
return 0;
}
You should use 1 one of these 4 choices:
int main(void);
int main();
int main(int argc, char **argv);
int main(int argc, char *argv[]);
where it's conventional to use the names argc and argv; you can change them but don't.
Take care never to use void main(void); which is too-often seen in production code.
By default main function returns an integer type, hence its "int main()" or you can give simply "main()"
"main(void)" is same as "main()", it tells the compiler that main function has no arguments.
In case if you want to pass arguments via main function:
int main(int argc, char *argv[]){
return 0;
}
main(){}
The above line give you an error. The default return type of any function in c is int. As the above code return nothing it gives you an error.
int main(){
//body
return 0;
}
In above code it fulfill all requirement so the above code will run.In above code we pass no argument in the function. So this function can take global and local variables to process.
int main(void)
{
//code
return 0;
}
In above code we pass no argument in the function. But specifying void tells the compiler that it does not take any argument. void is the default datatype of argument that signifies no input.

Return type of main function [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What should main() return in C/C++?
Difference between void main and int main?
I have always been using the main method in C like
void main(){ // my code }
and it works pretty well for me.
I also know about the other int return type:
int main(void)
int main()
int main(int argc, char *argv[])
But I have not been able to find any resource that says that I can use void as a return type. Every book suggests that the return type must be int or else it be omitted. Then why does void main() work?
Is this dependent on the version of C that I am using? Or does it work because I use a C++ IDE? Please reply specific to C and not C++.
Only book authors seem to be privy to the place where a return type of void for main() is allowed. The C++ standard forbids it completely.
The C standard says that the standard forms are:
int main(void) { ... }
and
int main(int argc, char **argv) { ... }
allowing alternative but equivalent forms of declaration for the argument types (and the names are completely discretionary, of course, since they're local variables to the function).
The C standard does make small provision for 'in some other implementation defined manner'. The ISO/IEC 9899:2011 standard says:
5.1.2.2.3 Program termination
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.
11) In accordance with 6.2.4, the lifetimes of objects with automatic storage duration declared in main
will have ended in the former case, even where they would not have in the latter.
This clearly allows for non-int returns, but makes it clear that it is not specified. So, void might be allowed as the return type of main() by some implementation, but you can only find that from the documentation.
(Although I'm quoting C2011 standard, essentially the same words were in C99, and I believe C89 though my text for that is at the office and I'm not.)
Incidentally, Appendix J of the standard mentions:
J.5 Common extensions
The following extensions are widely used in many systems, but are not portable to all
implementations. The inclusion of any extension that may cause a strictly conforming
program to become invalid renders an implementation nonconforming. Examples of such
extensions are new keywords, extra library functions declared in standard headers, or
predefined macros with names that do not begin with an underscore.
J.5.1 Environment arguments
In a hosted environment, the main function receives a third argument, char *envp[],
that points to a null-terminated array of pointers to char, each of which points to a string
that provides information about the environment for this execution of the program
(5.1.2.2.1).
Why does void main() work?
The question observes that void main() works. It 'works' because the compiler does its best to generate code for programs. Compilers such as GCC will warn about non-standard forms for main(), but will process them. The linker isn't too worried about the return type; it simply needs a symbol main (or possibly _main, depending on the system) and when it finds it, links it into the executable. The start-up code assumes that main has been defined in the standard manner. If main() returns to the startup code, it collects the returned value as if the function returned an int, but that value is likely to be garbage. So, it sort of seems to work as long as you don't look for the exit status of your program.
From the horse's mouth:
5.1.2.2.1 Program startup
1 The function called at program startup is named main. The implementation declares no
prototype for this function. It shall be defined with a return type of int and with no
parameters:
int main(void) { /* ... */ }
or with two parameters (referred to here as argc and argv, though any names may be
used, as they are local to the function in which they are declared):
int main(int argc, char *argv[]) { /* ... */ }
or equivalent;9)
or in some other implementation-defined manner.
9) Thus, int can be replaced by a typedef name defined as int, or the type of argv can be written as
char ** argv, and so on.
The loophole is the "some other implementation-defined manner". An implementation may allow main to return void (or any other type), but it must explicitly document that such a signature is allowed. Otherwise the behavior is undefined, meaning the compiler can do anything it wants. The program may execute without any problems. It may execute, but leave the environment in a bad state. It may crash on exit. It may fail to load at all.
It is dependent on the compiler you are using, but void main is not compilable everywhere. I have seen compilers that won't compile a program with void main. I can not recall the particular case(for c), but I know for sure this happens in g++(yes I know this is c++).
The standard calls for main() to return int, but a lot of C compilers allow you to specify the return type of main() as void.
I recommend you get into the habit of returning int. Adding a
return 0;
to the end of your main() isn't too much effort.
I was acceptable in C89 but it is no longer considered "safe". Under C99, it is no longer acceptable.
http://faq.cprogramming.com/cgi-bin/smartfaq.cgi?id=1043284376&answer=1044841143

Is c function prototype mismatch merely a warning

please take a look at my codes below
#include <stdio.h>
void printOut()
{
static int i = 0;
if (i < 10)
{
printOut(i);
}
}
int main(int argc, char *argv[])
{
return 0;
}
i guess there should be an error due to my invoking the non-existed function prototype.Actually, the code compiles well with mingw5 compiler, which is weird for me, then i change to Borland Compiler, i get a warning message said that no printOut function prototype, is this only a warning ? What is more, the code executes well without any pop-up error windows.
In C, a function without any parameters can still take parameters.
That's why it compiles. The way to specify that it doesn't take any parameters is:
void printOut(void)
This is the proper way to do, but is less common especially for those from a C++ background.
Your program's behavior is undefined, because you define printOut() with no parameters, but you call it with one argument. You need to fix it. But you've written it in such a way that the compiler isn't required to diagnose the problem. (gcc, for example, doesn't warn about the parameter mismatch, even with -std=c99 -pedantic -Wall -Wextra -O3.)
The reasons for this are historical.
Pre-ANSI C (prior to 1989) didn't have prototypes; function declarations could not specify the expected type or number of arguments. Function definition, on the other hand, specified the function's parameters, but not in a way that the compiler could use to diagnose mismatched calls. For example, a function with one int parameter might be declared (say, in a header file) like this:
int plus_one();
and defined (say, in the corresponding .c file) like this:
int plus_one(n)
int n;
{
return n + 1;
}
The parameter information was buried inside the definition.
ANSI C added prototypes, so the above could written like this:
int plus_one(int n);
int plus_one(int n)
{
return n + 1;
}
But the language continued to support the old-style declarations and definitions, so as not to break existing code. Even the upcoming C201X standard still permits pre-ANSI function declarations and definitions, though they've been obsolescent for 22 years now.
In your definition:
void printOut()
{
...
}
you're using an old-style function definition. It says that printOut has no parameters -- but it doesn't let the compiler warn you if you call it incorrectly. Inside your function you call it with one argument. The behavior of this call is undefined. It could quietly ignore the extraneous argument -- or it could conceivably corrupt the stack and cause your program to die horribly. (The latter is unlikely; for historical reasons, most C calling conventions are tolerant of such errors.)
If you want your printOut() function to have no parameters and you want the compiler to complain if you call it incorrectly, define it as:
void printOut(void)
{
...
}
This is the one and only correct way to write it in C.
Of course if you simply make this change in your program and then add a call to printOut() in main(), you'll have an infinite recursive loop on your hands. You probably want printOUt() to take an int argument:
void printOut(int n)
{
...
}
As it happens, C++ has different rules. C++ was derived from C, but with less concern for backward compatibility. When Stroustrup added prototypes to C++, he dropped old-style declarations altogether. Since there was no need for a special-case void marker for parameterless functions, void printOut() in C++ says explicitly that printOut has no parameters, and a call with arguments is an error. C++ also permits void printOut(void) for compatibility with C, but that's probably not used very often (it's rarely useful to write code that's both valid C and valid C++.) C and C++ are two different languages; you should follow the rules for whichever language you're using.

Resources