Why compilation still work when inverting the main function argument position - c

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++?

Related

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

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.)

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.

Extremely simple C program won't compile in gcc compiler

I have the following program
main()
{
char a,b;
printf("will i get the job:");
scanf("%c",&a);
printf("%c",a);
printf("We did it");
}
I saved the file as Hope.c. When I try to compile the code above with the gcc compiler, I will get the following error:
Hope.c:In function 'main':
Hope.c:4:2:warning:incompatible implicit declaration of built-in function 'printf' [enabled by default]
Hope.c:5:2:warning:incompatible implicit declaration of built-in function scanf[enabled by default]
The compiler gives this error when I use printf() or scanf(), even in a simple "Hello world" program.
Is there something wrong with my code, or is there a problem with the compiler?
You're missing #include <stdio.h> at the top. Note that these were warnings, though, not errors. Your program should still have compiled as is.
Also, for good measure, you should write out the return type and parameters to main() and return a value at the end.
#include <stdio.h>
int main(void)
{
char a,b;
printf("will i get the job:");
scanf("%c",&a);
printf("%c",a);
printf("We did it");
return 0;
}
When you call functions that you're not familiar with, look at the man page and include the headers that are mentioned there. It's #include <stdio.h> in your case.
That's really extermely important, e.g. I have experienced printf( "%s", func( ) ) causing a segmentation fault although func() returned a valid null terminated string, but there was no prototype that declared the return type of func() as char * (doing a little bit research, we found that only the last four bytes of the 64 bit pointer have been passed to printf())
Yes, there's something wrong with the code. You're using the functions printf and scanf without declaring them.
The usual thing to do is use the declarations shipped with the compiler (because they're known to be correct) with
#include <stdio.h>
C.89/C.90 permits implicit declarations of functions. Your warning messages are informing you that you have not provided explicit declarations for scanf and printf. As has been mentioned, you can correct this by adding #include <stdio.h> to the beginning of your program. By not doing so, the behavior of your program is undefined.
Because scanf() and printf() have implicit declarations, they are treated as if their prototypes were given as:
extern int scanf ();
extern int printf ();
These declarations state that scanf() and printf() take an as of yet unknown number of arguments and return and int. However, this kind of declaration still assumes that these functions will take a fixed number of arguments. This is incompatible with their true prototypes, in which they take a variable number of arguments:
extern int scanf (const char *, ...);
extern int printf (const char *, ...);
Your C compiler apparently knows about the true prototypes of these functions because it treats those functions as "built-ins", meaning it can generate special case code when compiling to source code that calls those functions. Since the implicit declaration does not match its built-in knowledge of their prototypes, it generated the warning.
A compiler that did not have this "built-in knowledge" probably would not have generated the warning. It would then have generated code to call scanf() and printf() as if they took a fixed number of arguments. The error then may occur at runtime, since the calling convention for a function that takes a variable number of arguments may differ from the calling convention of a function that takes a fixed number of arguments.
This is all described in C.89 §3.3.2.2.
If the expression that precedes the parenthesized argument list in
a function call consists solely of an identifier, and if no
declaration is visible for this identifier, the identifier is
implicitly declared exactly as if, in the innermost block containing
the function call, the declaration
extern int identifier();
appeared.
...
If the expression that denotes the called function has a type that
does not include a prototype, the integral promotions are performed on
each argument and arguments that have type float are promoted to
double. ... If the function is defined with
a type that includes a prototype, and the types of the arguments after
promotion are not compatible with the types of the parameters, or if
the prototype ends with an ellipsis ( ", ..." ), the behavior is
undefined.
Note that C.99 removes the allowance for implicit function declarations.

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.

Not including stdlib.h does not produce any compiler error!

Hopefully this is a very simple question. Following is the C pgm (test.c) I have.
#include <stdio.h>
//#include <stdlib.h>
int main (int argc, char *argv[]) {
int intValue = atoi("1");
double doubleValue = atof("2");
fprintf(stdout,"The intValue is %d and the doubleValue is %g\n", intValue, doubleValue);
return 0;
}
Note that I am using atoi() and atof() from stdlib.h, but I do not include that header file. I compile the pgm (gcc test.c) and get no compiler error!
I run the pgm (./a.out) and here is the output, which is wrong.
The intValue is 1 and the doubleValue is 0
Now I include stdlib.h (by removing the comments before the #include) and recompile it and run it again. This time I get the right output:
The intValue is 1 and the doubleValue is 2
How come the compiler did not complain about not including the stdlib.h and still let me use the atoi(), atof() functions?
My gcc info:
$ gcc --version
gcc (GCC) 4.1.2 20070925 (Red Hat 4.1.2-27)
Any thoughts appreciated!
For historical reasons -- specifically, compatibility with very old C programs (pre-C89) -- using a function without having declared it first only provokes a warning from GCC, not an error. But the return type of such a function is assumed to be int, not double, which is why the program executes incorrectly.
If you use -Wall on the command line, you get a diagnostic:
$ gcc -Wall test.c
test.c: In function ‘main’:
test.c:5: warning: implicit declaration of function ‘atoi’
test.c:6: warning: implicit declaration of function ‘atof’
You should use -Wall basically always. Other very useful warning options for new code are -Wextra, -Wstrict-prototypes, -Wmissing-prototypes, -pedantic, and -Wwrite-strings, but compared to -Wall they have much higher false positive rates.
Tangentially: never use atoi nor atof, they hide input errors. Use strtol and strtod instead.
If you don't specify otherwise, I believe a C compiler will just guess that undeclared functions take the form extern int foo(). Which is why atoi works and atof doesn't. Which compiler flags were you using? I suggest using -Wall to turn on a bunch of gcc warnings, which should include referencing undeclared functions.
C allows you to call a function without having a declaration for that function.
The function will be assumed to return an int and arguments will be passed using default promotions. If those don't match what the function actually expects, you'll get undefined behavior.
Compilers will often warn for this case, but not always (and that will also depend on compiler configuration).
In C, when you use a function that was not declared, it assumes that it has the default prototype:
int FUNCTION_NAME();
Note that in C using () as prototype means it accepts any arguments.
If you compile with the flag -Wall (I recommend you to always use this flag, since it enables all recommended warnings) you will get a warning (not an error) telling you that you are using an undeclared function.
C, unfortunately, does not require functions to be prototyped (or even declared) before use -- but without a prototype, it automatically makes certain assumptions about the function. One of those is that it returns an int. In your case, atoi does return an int, so it works correctly. atof doesn't, so it doesn't work correctly. Lacking a prototype/declaration, you get undefined behavior -- typically it'll end up retrieving whatever value happens to be in the register where an int would normally be returned, and using that. It appears that in your particular case, that happens to be a zero, but it could just as easily be something else.
This is one of the reasons many people push "C++ as a better C" -- C++ does require that all functions be declared before use, and further that you specify the types of all (non-variadic) parameters as well (i.e. a C++ function declaration is like a C prototype, not like a C declaration).

Resources