What is the purpose of "int main(void *framep)"? - c

In C, main() function takes only zero or two arguments.If we provide two arguments,then first argument must be int type.
int main(int argc, char *argv[])
But, I saw following code, when browsing OpenBSD.
int main(void *framep){}
Is it valid in C?
GCC compiler gives following warnings:
prog.c:3:5: warning: first argument of 'main' should be 'int' [-Wmain]
int main(void *p) {
^~~~
prog.c:3:5: warning: 'main' takes only zero or two arguments [-Wmain]
What is the purpose of it?

On Linux, during linkage, the library function _start is to be linked to a function main() that is expected to be present in your code.
Then traditionally your main is called by _start with int argc, char *argv[], the number of arguments (including program name) and the actual arguments (plus a trailing NULL).
However on some other implementations, there might be no need to call main this way, or for performance reasons call it with a reduced number of arguments, following a different format.
main() is the starting function of our programs and is passed argc, argv, but after all, it's only a C function and may be passed something else, as long as the convention, on that implementation, is known and accepted.

Oups, this is not a normal program but a kernel, so the normal rules for main do not really apply. When the program starts, no environment exists to pass argument values, and the return value of main will not be used either because when the kernel exits, nothing else exists. One comment says that the definition was modified to only cope with gcc requirements:
return int, so gcc -Werror won't complain
That is explicit in N1256 draft for C11 at 5.1.2.1 Freestanding environment :
In a freestanding environment (in which C program execution may take place without any
benefit of an operating system), the name and type of the function called at program
startup are implementation-defined. Any library facilities available to a freestanding
program, other than the minimal set required by clause 4, are implementation-defined.
The effect of program termination in a freestanding environment is implementationdefined.
As at kernel startup no OS still exists, so it actually runs in a freestanding environment. That probably means that is also needs to be compiled with special flags...

In the link you provide, framep is not used inside the main function.
And no, it's not standard.
GCC issues warnings as you saw already, but it's worth noting that clang throws an error:
error: first parameter of 'main' (argument count) must be of type 'int'
int main(void *framep){}
^
1 error generated.
From the Standard:
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) or in some other implementation-defined manner.

You compiled it with g++ to get those errors, if you compile it with gcc you don't get them.
$ gcc test.c
$ g++ test.c
test.c:3:5: warning: first argument of 'int main(void*)' should be 'int' [-Wmain]
int main(void *framep)
^~~~
test.c:3:5: warning: 'int main(void*)' takes only zero or two arguments [-Wmain]
This is important because C doesn't consider the argument types (or number!) to be part of the type of the function (whereas C++ does). There are various reasons, among them being that in C, the caller cleans up the arguments, so if he specifies too many, he also cleans them up. In C++, the callee cleans up arguments, so if he cleans up the wrong number, you end up with a corrupted stack.
On to why you might choose to use int main(void *framep): In the calling convention for C, the arguments are pushed onto the stack, and then the call is made, which places the return address next. The callee will then typically push the old value of EBP, then move the stack pointer into EBP as the "base pointer" for the new stack frame. Then the stack pointer is moved to allocate space of any automatic (local) variables in the callee. I.e., the stack looks like this:
Arg n
Arg n-1
...
Arg 1
Return Addr
Old EBP
Callee locals
Now assume that we'd like to inspect the return address for our function, or read the prior frame pointer (Old EBP) that was pushed. If we were writing in assembly, we'd just dereference relative to the current frame pointer (EBP). But we're writing in C. One way to get a reference would be to take the address of the first argument. That is, &framep, which is the place where Arg1 lives on the stack. Thus (&framep)[-2] should be a void * pointing to the stored prior frame pointer (Old EBP).
(Note: I am assuming Intel architecture, where all pushes to the stack are extended to pointer size by the hardware.)

Related

Why does `main` end with `ret` and not `ret 4`?

Consider the following empty C program (the standard guarantees that the compiler does an implicit return 0):
int main(int argc, char* argv[]) {}
You can add any logic into this function that manipulates argc and argv. Yet, when main finishes, its assembly code will just do a simple ret instead of ret 4. I am expecting to see a ret 4 because in my mind main is the callee of some other function and therefore must clean up its two arguments from the stack: and int and a pointer to char array. Why does it not do so?
Most compilers choose to have the caller clean the arguments from the stack; a tradition that dates from early C compilers and handling number of arguments. At the call-site, the compiler knows how many it pushed, so it is trivial for it to adjust the stack.
Also, note that historically main can be specified with 0-3 (arge) arguments. Again, the caller (eg. _start) can just provide 3 and let the implementor choose.

Why compilation still work when inverting the main function argument position

Why my C program doesn't work when I declare the main function like this (I inverted the arguments position) :
int main(char * argv, int argc){
}
I compiled it without problem but I got errors when I run it.
Thanks.
Due to the incorrect main() signature, this is not a valid C program.
Try enabling compiler warnings. My compiler tells me about the problem:
$ gcc -Wall test.c
test.c:1:5: warning: first argument of 'main' should be 'int' [-Wmain]
test.c:1:5: warning: second argument of 'main' should be 'char **' [-Wmain]
See What are the valid signatures for C's main() function?
Unlike in C++, functions in C are solely identified by their names, not their arguments. E.g. linker will be pretty happy when it sees a 'main' function.
Nevertheless, there are certain assumptions how main() is called by the operating system resp. the runtime environment. When your parameters are wrong, your program will see unexpected values and might crash.
And btw, you probably will see errors or warnings when you enable diagnostics (e.g. '-Wall -W') when building the program.
This is an incorrect main() signature. You may check the main function.
The parameters argc, argument count, and argv, argument vector,1
respectively give the number and values of the program's command-line
arguments. The names of argc and argv may be any valid identifier in
C, but it is common convention to use these names.
Also check What should main() return in C and C++?

Non-standard signature of main() compiles successfully

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.

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 declaring an header file essential?

Is declaring an header file essential? This code:
main()
{
int i=100;
printf("%d\n",i);
}
seems to work, the output that I get is 100. Even without using stdio.h header file. How is this possible?
You don't have to include the header file. Its purpose is to let the compiler know all the information about stdio, but it's by no means necessary if your compiler is smart (or lazy).
You should include it because it's a good habit to get into - if you don't, then the compiler has no real way to know if you're breaking the rules, such as with:
int main (void) {
puts (7); // should be a string.
return 0;
}
which compiles without issue but rightly dumps core when running. Changing it to:
#include <stdio.h>
int main (void) {
puts (7);
return 0;
}
will result in the compiler warning you with something like:
qq.c:3: warning: passing argument 1 of ‘puts’ makes pointer
from integer without a cast
A decent compiler may warn you about this, such as gcc knowing about what printf is supposed to look like, even without the header:
qq.c:7: warning: incompatible implicit declaration of
built-in function ‘printf’
How is this possible? In short: three pieces of luck.
This is possible because some compilers will make assumptions about undeclared functions. Specifically, parameters are assumed to be int, and the return type also int. Since an int is often the same size as a char* (depending on the architecture), you can get away with passing ints and strings, as the correct size parameter will get pushed onto the stack.
In your example, since printf was not declared, it was assumed to take two int parameters, and you passed a char* and an int which is "compatible" in terms of the invocation. So the compiler shrugged and generated some code that should have been about right. (It really should have warned you about an undeclared function.)
So the first piece of luck was that the compiler's assumption was compatible with the real function.
Then at the linker stage, because printf is part of the C Standard Library, the compiler/linker will automatically include this in the link stage. Since the printf symbol was indeed in the C stdlib, the linker resolved the symbol and all was well. The linking was the second piece of luck, as a function anywhere other than the standard library will need its library linked in also.
Finally, at runtime we see your third piece of luck. The compiler made a blind assumption, the symbol happened to be linked in by default. But - at runtime you could have easily passed data in such a way as to crash your app. Fortunately the parameters matched up, and the right thing ended up occurring. This will certainly not always be the case, and I daresay the above would have probably failed on a 64-bit system.
So - to answer the original question, it really is essential to include header files, because if it works, it is only through blind luck!
As paxidiablo said its not necessary but this is only true for functions and variables but if your header file provides some types or macros (#define) that you use then you must include the header file to use them because they are needed before linking happens i.e during pre-processing or compiling
This is possible because when C compiler sees an undeclared function call (printf() in your case) it assumes that it has
int printf(...)
signature and tries to call it casting all the arguments to int type. Since "int" and "void *" types often have same size it works most of the time. But it is not wise to rely on such behavior.
C supprots three types of function argument forms:
Known fixed arguments: this is when you declare function with arguments: foo(int x, double y).
Unknown fixed arguments: this is when you declare it with empty parentheses: foo() (not be confused with foo(void): it is the first form without arguments), or not declare it at all.
Variable arguments: this is when you declare it with ellipsis: foo(int x, ...).
When you see standard function working then function definition (which is in form 1 or 3) is compatible with form 2 (using same calling convention). Many old std. library functions are so (as desugned to be), because they are there form early versions of C, where was no function declarations and they all was in form 2. Other function may be unintentionally be compatible with form 2, if they have arguments as declared in argument promotion rules for this form. But some may not be so.
But form 2 need programmer to pass arguments of same types everywhere, because compiler not able to check arguments with prototype and have to determine calling convention osing actual passed arguments.
For example, on MC68000 machine first two integer arguments for fixed arg functions (for both forms 1 and 2) will be passed in registers D0 and D1, first two pointers in A0 and A1, all others passed through stack. So, for example function fwrite(const void * ptr, size_t size, size_t count, FILE * stream); will get arguments as: ptr in A0, size in D0, count in D1 and stream in A1 (and return a result in D0). When you included stdio.h it will be so whatever you pass to it.
When you do not include stdio.h another thing happens. As you call fwrite with fwrite(data, sizeof(*data), 5, myfile) compiler looks on argruments and see that function is called as fwrite(*, int, int, *). So what it do? It pass first pointer in A0, first int in D0, second int in D1 and second pointer in A1, so it what we need.
But when you try to call it as fwrite(data, sizeof(*data), 5.0, myfile), with count is of double type, compiler will try to pass count through stack, as it is not integer. But function require is in D1. Shit happens: D1 contain some garbage and not count, so further behaviour is unpredictable. But than you use prototype defined in stdio.h all will be ok: compiler automatically convert this argument to int and pass it as needed. It is not abstract example as double in arument may be just result of computation involving floating point numbers and you may just miss this assuming result is int.
Another example is variable argument function (form 3) like printf(char *fmt, ...). For it calling convention require last named argument (fmt here) to be passed through stack regardess of its type. So, then you call printf("%d", 10) it will put pointer to "%d" and number 10 on stack and call function as need.
But when you do not include stdio.h comiler will not know that printf is vararg function and will suppose that printf("%d", 10) is calling to function with fixed arguments of type pointer and int. So MC68000 will place pointer to A0 and int to D0 instead of stack and result is again unpredictable.
There may be luck that arguments was previously on stack and occasionally read there and you get correct result... this time... but another time is will fail. Another luck is that compiler takes care if not declared function may be vararg (and somehow makes call compatible with both forms). Or all arguments in all forms are just passed through stack on your machine, so fixed, unknown and vararg forms are just called identically.
So: do not do this even you feel lucky and it works. Unknown fixed argument form is there just for compatibility with old code and is strictly discouraged to use.
Also note: C++ will not allow this at all, as it require function to be declared with known arguments.

Resources