I have been thinking a lot about the most honest way to minimally express the main function in C(Yes, it's trivial and usually not interesting, but it's interesting to me).
For a long time, to this day, I prefer defining main as follows:
int main(int argc, char **argv)
{
return 0;
}
My issue with this is that I usually never use those arguments, so it makes the arguments explicit, even though I don't care enough about them in the code to write them out.
So I started doing
int main()
{
return 0;
}
This is honest, since it does not explicitly say that the function has no arguments, as many do in int main(void){} definition, and i'm satisfied with it.
However, I just had an idea that using variadic definition of main makes the definition of main more comfortable for me because it "looks" to me as though the function does have arguments, but I don't care about them right now.
int main(...)
{
return 0;
}
Is there any issue with such an abuse of notation for ...? That is, ... is meant to be used for functions of pattern (, argument from which number of following arguments can be deduced, ...). Whereas this main does not fit this pattern, and is technically a misuse of notation.
I understand the notation is misleading to other readers(... is somewhat of an advanced concept, and being abused makes it more misleading), and I will still prefer the other prototypes when sharing the code. I am merely curious on whether it is valid C to do that.
The questions I have are:
Is the variadic definition of main portable or is it possible that some compiler will not like it.
Is it generally okay to do this kind of definition, or are runtime/compile-time consequences to doing so?
No, that is absolutely wrong.
It is wrong because it is invalid syntax. From n1548 section 6.7.6:
parameter-type-list:
parameter-list
parameter-list , ...
parameter-list:
parameter-declaration
parameter-list , parameter-declaration
According to the C standard, if you use ... in function arguments, you must have at least one other argument before it. Anything else is invalid C. You can see from the grammar that ... can only appear after a comma , and a parameter-list, and parameter-list cannot be empty.
Your compiler may accept it, but that doesn't mean much. Compilers accept lots of things which are invalid C and happily compile them anyway.
Your first two versions are fine. Use whichever meets your needs.
int main(...) would not a good signature for this function, though, even if it were valid!
... means that the function takes a variable number of arguments of unspecified types. Take printf() for example. It receives a format string followed by zero or more arguments of any type, and its function signature reflects this:
int printf( const char* format, ... )
The main function is not like that. It receives a specific list of arguments of specific types, not a variable number of arguments with types that must be determined at runtime.
Traditionally, main took two arguments as shown in your first example:
int main( int argc, char **argv )
Of course you can ignore those arguments by either not using them, or by defining main as in your second example: int main().
Depending on the compiler/runtime, main may take a third argument containing the environment variables:
int main( int argc, char *argv[], char *env[] )
It may even take a fourth argument on OSX:
int main( int argc, char **argv, char **envp, char **apple )
But in all these cases, you have specific arguments of specific types. main isn't like printf - it never takes a truly variable number of arguments of uncertain types. So main(...) is not an appropriate signature.
Related
So I'm learning about functions in a book.
It says we need to prototype or declare functions so the compiler can understand if they are correctly called or not.
But why does the main function works without a prototype?
I used to write main functions in my learning process like this:
int main(void)
So it will not get any argument because of (void)
I tried to run my program with argument for example > ./a.out 2
int main(int y){
printf("%s %d\n","y is",y);
}
When I run it normally y is 1, when run it with > ./a.out 1 y is 2, when there is more than one argument it increases by one. So it's not the right way but what causes this?
Declaring y as char says nothing so my guess is it works like the return value of scanf(). It returns number of successful inputs.
A function must be either declared (i.e. a prototype) or defined before it is called. The main function is different from other functions in that it's called by the program startup code and not some other function.
There are however restrictions on what the signature of main can be. On a regular hosted implementation, the C standard says it can be either:
int main(void)
Or:
int main(int argc, char **argv)
The latter case is used to read command line arguments. argc contains the number of arguments passes, including the program name. argv contains the actual arguments as an array of char *.
Many systems also support:
int main(int argc, char **argv, char **envp)
Where envp contains the environment variables known to the program.
The prototype you're using: int main(int y) is not supported in any implementation I'm aware of, so attempting to use such a prototype for main invokes undefined behavior.
When I run it normally y is 1, when run it with > ./a.out 1 y is 2, when there is more than one argument it increases by one. So it's not the right way but what causes this?
The standard entry for program startup kind of answers both your questions:
N1570 § 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[]) { /* ... */ }
[...]
As dbush already stated in the accepted answer these are the only two main implementations allowed by the standard.
The standard leaves the responsability of dealing with undefined constructs opened and imposes no requirements for what the behavior should be, a given implementation may deal with the situation in any way it considers appropriate, this is known as undefined behavior.
What seems to be happening is that your compiler is assuming that y is argc, which is allowed (as you can see in the second snippet of highlighted citation above), and argc stores the number of arguments in the command line, which is consistent with the results you're having, but again, this behavior may differ in different compilers, systems or even versions of the same compiler.
Recently I got a question when writing a program for file opening.
Let me explain my question clearly. Here I'm taking open call as an example.
To create a file:
open("file_name", O_CREAT, 0766); //passing 3 parametrs
To open a file:
open("file_name", O_RDWR); //only 2 arguments.
Then I clearly observed this point and it also works for main() too.
main(void) //worked
main(int argc, char **argv); //worked
main(int argc) //worked and it's doesn't give an error like "too few arguments".
main() //worked
So how we can create these optional arguments? How exactly can the compiler validate these prototypes? If possible, please write an example program.
The open function is declared as a variadic function. It will look something like this:
#include <stdarg.h>
int open(char const * filename, int flags, ...)
{
va_list ap;
va_start(ap, flags);
if (flags & O_CREAT)
{
int mode = va_arg(ap, int);
// ...
}
// ...
va_end(ap);
}
The further arguments are not consumed unless you have indicated that they do in fact exist.
The same construction is used for printf.
The manual doesn't always make this explicit, since the only possible two signatures are (char const *, int) and (char const *, int, int), so there's little point in revealing that you the function actually accepts variable arguments. (You can test this by trying to compile something like open("", 1, 2, 3, 4, 5, 6).)
In all cases, a varargs function must be able to determine somehow, from the fixed arguments, how many variable arguments there are. For example, the printf() family of functions use the format string to determine the number and types of the arguments. The execl() function uses a sentinel (null pointer) to mark the end of the argument list. It would be possible to use a count instead of a sentinel (but if you're going to do that, the chances are that a count and an array in a non-varargs function would work as well as, if not better than, a count and a list of arguments). The open() function uses one of the flag bits to determine whether the mode should be present — see Kerrek SB's answer.
The main() function is a special case. The implementation (compiler) is prohibited from declaring a prototype for it, and must accept at least the two forms:
int main(int argc, char **argv);
int main(void);
or their equivalents. It may accept other forms too; see What's the use of the third environment variable in the C main()? for one common form. In C, but not C++, a standard compiler can document other return types — and Microsoft has documented void as a valid return type from VS 2008 onwards.
Because there is no implementation-provided prototype for main(), the compiler can't officially reject any declarations/definitions of main(), though it might pass comment on forms it doesn't recognize (GCC does comment on main() functions that do not return an int type, for example).
Was browsing the source code for sudo as provided on this site, and came across this super weird type signature (Bonus question: is there a more C-like term for "type signature"?) for main:
int
main(argc, argv, envp)
int argc;
char **argv;
char **envp;
{
I understand that the style itself is the oldskool K&R. What I'm really interested in is the fact that main is taking a bonus argument, char **envp. Why? sudo is a fairly standard command line tool and is invoked as such. How does the operating system know what to do when it comes across a main function that isn't defined with the usual (int argc, char *argv[])?
Many a time I myself have been lazy and just left off the arguments completely and whatever program I was writing would appear to work just fine (most dangerous thing that can happen with C, I know :p)
Another part of my question is, what cool stuff does all this allow you to do? I have a hunch it helps a heap with embedded programming, but I've sadly had minimal exposure to that and can't really say. I would love to see some concrete examples
It's just a pointer to the environment, identical to
extern char **environ;
Both have been available in unix since Version 7 (in Version 6 there were no environment variables). The extern named environ got standardized; the third argument to main didn't. There's no reason to use 3-arg main except as some kind of fashion statement.
The process setup code that calls main doesn't need to know whether main expects 3 arguments, because there's no difference at the assembly level between a function that takes 2 arguments and a function that takes 3 arguments but doesn't use the third one. Or between a function that takes no arguments and a function that takes 2 arguments and doesn't use them, which is why int main(void) also works.
Systems with a not-unix-like ABI may need to know which kind of main they're calling.
Put this in one file:
#include <stdio.h>
int foo(int argc, char **argv)
{
int i;
for(i=0;i<argc;++i)
puts(argv[i]);
return 0;
}
And this in another:
extern int foo(int argc, char **argv, char **envp);
int main(int argc, char **argv)
{
char *foo_args[] = { "foo", "arg", "another arg" };
char *foo_env[] = { "VAR=val", "VAR2=val2" };
foo(3, foo_args, foo_env);
return 0;
}
This is completely wrong from a cross-platform language-lawyer standpoint. We've lied to the compiler about the type of foo and passed it more arguments than it wants. But in unix, it works. The extra argument just harmlessly occupies a slot on the stack that is properly accounted for and cleaned up by the caller after the function returns, or temporarily exists in a register where the callee doesn't expect to find anything in particular, and which the caller expects the callee to clobber so it doesn't mind if the register gets reused for another purpose in the callee.
That's exactly what happens to envp in a normal C program with a 2-arg main. And what happens to argc and argv in a program with int main(void).
But just like envp itself, there's no good reason to take advantage of this in serious code. Type checking is good for you, and knowing you can evade it should go along with knowing that you shouldn't.
http://en.wikipedia.org/wiki/Main_function
From the very first paragraph:
Other platform-dependent formats are also allowed by the C and C++ standards, except that in C++ the return type must always be int;[3] for example, Unix (though not POSIX.1) and Microsoft Windows have a third argument giving the program's environment, otherwise accessible through getenv in stdlib.h:
Google is your friend. Also, the operating system doesn't need to know anything about the main in this case - it's the compiler that does the work, and as long as it's valid argument which are accepted by the compiler then there is no problem.
What does the following mean :
int main(void) {...}
VS
int main() {...}
?
I think that int main() {...} means that main doesn't receive any parameters (from command line) , however:
int main(int argc, char *argv[])
does.
But, what does int main(void) {...} mean? And, what does void stand for ?
I've looked here but it's somehow a different question .
In C++, there is no difference.
In C, the difference is questionable. Some love to argue that the latter version (the one without void) is technically just a common implementation extension and not guaranteed to work by the standard because of the wording in the standard. However, the standard clearly states that in a function definition an empty set of parameters has a well-defined behaviour: that the function does not take any parameters. Thus such a definition for main matches the following description in the standard:
It [main] shall be defined with a return type of int and with no parameters.
There is, however, a noticeable difference between the two: namely, the version without void fails to provide a correct prototype for the function:
// this is OK.
int main()
{
if (0) main(42);
}
// this requires a diagnostic to be shown during compiling
int main(void)
{
if (0) main(42);
}
Oh, and just to be complete: the void has the following meaning in all function declarators:
(6.7.6.3p10) The special case of an unnamed parameter of type void as the only item in the list specifies that the function has no parameters.
First of all, there is a difference of what is allowed for hosted systems and freestanding systems, as shown here.
For hosted systems, 5.1.2.2.1 Program startup applies:
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)
... (more text follows regarding argv/argc etc styles).
The interesting part is "with no parameters". int main() and int main (void) are currently equivalent, since they are both function declarators and have no parameters. The following applies (6.7.6.3 ):
10 The special case of an unnamed parameter of type void as the only item in the list specifies that the function has no parameters.
/--/
14 An identifier list declares only the identifiers of the parameters of the function. An empty
list in a function declarator that is part of a definition of that function specifies that the
function has no parameters. The empty list in a function declarator that is not part of a
definition of that function specifies that no information about the number or types of the
parameters is supplied.145)
Emphasis mine, the bold text is what applies to int main(). There is also note 145) at the end of the text, which says "See ‘‘future language directions’’ (6.11.6)":
6.11.6 Function declarators
The use of function declarators with empty parentheses (not prototype-format parameter type declarators) is an obsolescent feature.
And here is the difference. Being a function declarator, int main() is bad style because of the above, since it is not guaranteed to work in the next version of the C standard. It is flagged as an obsolescent feature in C11.
You should therefore always use int main (void) on a hosted system and never int main(), even if the two forms are, for now, equivalent.
In C++ both forms are completely equivalent, but there int main() is the preferred style for subjective, cosmetic reasons (Bjarne Stroustrup says so... which is probably quite a bad rationale for explaining why you do something in a particular way).
In C, in a prototype (not in C++ though) an empty argument list means that the function could take any arguments (in the definition of a function, it means no arguments). In C++, an empty parameter list means no arguments. In C, to get no arguments, you have to use void. See this question for a better explanation.
In C++ having a function foo(void) and foo() is the same thing. However, in C it's different: foo(void) is a function that has no arguments, while foo() is a function with unspecified arguments.
In C++, there is no difference, both are same.
Both definitions work in C also, but the second definition with void is considered technically better as it clearly specifies that main can only be called without any parameter.
In C, if a function signature doesn’t specify any argument, it means that the function can be called with any number of parameters or without any parameters. For example, try to compile and run following two C programs (remember to save your files as .c).
In C++, there is no difference between the two, and int main() is a legal signature and return type for main.
I know the thread is old but this question was bothering me for a while a few years ago so I wanted to throw in my half a cent(if that).
I always treat C functions as if they have fixed amount of arguments regardless of context, unless they use va_args. That is, I trust main to ALWAYS have the prototype:
int main(int argc, char **argv).
even if no arguments are passed, the function has these arguments on the stack because the main function does not have function overloading.
C does have the ability to have primitive overloading through just pretending the argument is not there. In which case, the argument is still passed and is on the stack but you never access it, so it merely reduces size of the source code.
Saying int main() simply means that I know that the function may have parameters, but I am not using them, so I write int main().
Saying int main(void) says that main CERTAINLY has no arguments, and implies that there are two different function prototypes:
int main(void);
int main(int argc, char **argv);
Since C has no function overloading, this is somewhat misleading to me, and I distrust code that has main(void) in it. I would not if main NEVER took any parameters, in which case main(void) would be completely OK.
NOTE: In some implementations, there are more parameters in main than argc and argv, such as env, but this does not bother me because I know that I do not explicitly say that those are the only two parameters, but those are the minimal parameters and it's okay to have more, but not less. This is in contrast to downright saying int main(void) which yells at me as THIS FUNCTION HAS NO PARAMETERS, which isn't true, since it does, they are just omitted.
Here is my basis code:
/* sample.c - build into sample. */
#include <stdio.h>
int main(void)
{
int _argc = *((int *)2686800);
char ***_pargv = (char ***)2686804;
int i;
for (i = 1; i < _argc; ++i) {
printf("%s ", (*_pargv)[i]);
}
return 0;
}
./sample I clearly have arguments
The function clearly has arguments passed to it, despite going out of the way to explicitly say that it doesn't by typing void into the function prototype.
As eq- says above:
(6.7.6.3p10) The special case of an unnamed parameter of type void as the
only item in the list specifies that the function has no parameters.
Thus saying that the function has void as an argument but actually having arguments on the stack is a contradiction.
My point is that arguments are still there, so explicitly asserting that main is void of arguments is dishonest. The honest way would be to say int main(), which claims nothing about how many parameters it has, only how many parameters you are care about.
NOTE2: The _argc, _pargv are system dependent, to find your values you must find them out by running this program:
/* findargs.c */
#include <stdio.h>
int main(int argc, char **argv)
{
printf("address of argc is %u.\n", &argc);
printf("address of argv is %u.\n", &argv);
return 0;
}
These values should remain correct for your specific system.
In C++, there is no difference between int main() and int main(void).
But in C they are little bit different.
int main() indicates that the main function can be called with any number of parameters or without any parameter. On the other hand, int main(void) indicates that the main function will be called without any parameter
#include <stdio.h>
int main()
{
static int i = 5;
if (--i){
printf("%d ", i);
main(10);
}
}
Output: 4 3 2 1
#include <stdio.h>
int main(void)
{
static int i = 5;
if (--i){
printf("%d ", i);
main(10);
}
}
It will show error. Because, in int main(void) parameter is void but in the program we have taken main(10) (which defines some value, not void)
Technically, if your host is partially POSIX compliant, then you have
int main(); // this legacy is always used by the run time library
int main(int argc); // illegal by compiler
int main(int argc, char** argv); // required by C standards
int main(int argc, char** argv, char** envp); // required by POSIX standard
If you have a Mac, there is also this
int main(int argc, char** argv, char** envp, char** apple); // required by Macintosh standard
Your host will send all the arguments, so a host will always send argc, argv, and envp (and apple if you are using an Apple product), but the programmer could have their main declared as taking void. The implicit function pointer typecast is technically an undefined behavior.
To prevent the typecast undefined behavior, int main() is a neutral form that means it could take any fixed number of arguments using canonical type promotion (int or larger, and double or larger) and int main(int argc, ...) means it could take any variable number of arguments also with canonical type promotion. In other words, the form return_type function_name() is an exception to undefined behavior.
In C++:
ㅤㅤint main() and int main(void) are the same in C++. They both take 0 and only 0 parameters.
In C:
ㅤㅤint main() takes as many arguments as you want. The function just won't use them. intㅤㅤㅤ main(void) makes it so passing an argument will create an error and make it impossible to ㅤㅤpass arguments.
ㅤ
So today I figured (for the first time admittedly) that int foo() is in fact different from int foo(void) in that the first one allows any number of inputs and the second one allows zero.
Does int foo() simply ignore any given inputs? If so, what's the point of allowing this form of function? If not, how can you access them and how is this different from having a variable argument list (e.g. something like int foo (int argc, ...))?
The key to understanding this is understanding the call stack. What happens when you call a function in C (with the standard x86 ABI — other platforms may vary) is that the caller pushes all of the arguments, in reverse order, onto the stack before calling the callee. Then, the callee can read as many of those arguments as it wants. If you use foo(void), obviously you won't read any. If you use foo(int), you'll be able to read one word into the stack below your current frame.
Using foo() (with no args specified) means that the compiler won't care to check the arguments you pass to foo. Anything goes; there's no contract. This can be useful if foo has two different implementations that take different types as arguments, and I want to be able to switch them out programmatically. (It's also sometimes useful when writing functions in assembler, where you can handle the stack and arguments yourself.) But remember that the compiler is not going to do any type-checking for you, so you have to be very careful.
This is different from foo(int, ...), since in that case, the function actually has a way to access all of the arguments (using varargs). There's no reason ever to actually define a function with foo(), since it's basically equivalent to foo(void). foo() is only useful for declarations.
First, take int foo(). This form is a function declaration that does not provide a prototype - that is, it doesn't specify the number and types of its arguments. It is an archaic form of function declaration - it's how functions were originally declared in pre-ANSI C. Such a function however does have a fixed number and type of arguments - it's just that the declaration doesn't tell the compiler what it is, so you are responsible for getting it right where you call the function. You declare such a function with arguments like so:
int foo(a, b)
int a;
char *b;
{
return a + strlen(b);
}
This form of function declaration is now obsolete.
int foo(void) is a modern declaration that provides a prototype; it declares a function that takes no arguments. int foo(int argc, ...) also provides a prototype; it declares a function that has one fixed integer argument and a variable argument list.
In standard conform C, you have to use int foo(void) if the function does not accept any parameters.
I guess it is compiler dependant what happens, when you pass arguments to a function with empty braces. But I don't think there is a way to access these parameters.
As for main, the only standard conform (pure c) ways to write them are either int main(void) or int main(int argc, char **argv) (or char *argv[] which is the same).
Well, in C++ the two forms are equivalent and they both declare a function that takes no arguments. If you try to call the function and pass in an argument, the compile will give an error.
On the other hand, C and Objective-C both treat the two forms differently. In these languages the first form declares a function that takes an unknown number of arguments, whereas the second form declares a function that takes no arguments at all. So, in C the following is valid code:
int foo() {
return 5;
}
int main() {
return foo(1, 2, 3);
}
The compiler doesn't complain, and the code runs fine (a C++ compiler would give an error on this same code).
Generally what you want in C and Objective-C is to use the second form and include the explicit void to indicate that the function should take no arguments. However, it's more common in C++ to use the first form because it's equivalent and shorter.