How is this pre-standard function declaration compiled with modern compiler? - c

I found the following declaration code in the very early sources of C compiler
main(argc, argv)
int argv[]; {
return 0;
}
I tried to run it on ideone.com compiling it in "C" mode with gcc-4.7.2 and it compiles fine and even runs successfully
result: Success time: 0s memory: 1828 kB returned value: 0
Now I'm aware that there was a pre-standard way of declaring function parameters this way:
int funct(crc, buf, len)
int crc;
register char* buf;
int len;
{
//function implementation
}
but in the latter style it's quite clear - the parameters are first just listed, then declared as if they were a kind of local variables and I see all the parameters declared and the return type.
Back to the first code
main(argc, argv)
int argv[]; {
return 0;
}
in the former code there're two parameters listed and only one declared and it looks like argv has type array of int.
How is it being treated by the compiler?

You are talking about pre-ANSI C, and the style of prototype known as K&R prototypes. For such function declarations, parameters and return values whose types are not specified are deemed to be of type int.

It is K&R C syntax where compiler won't check the types of arguments and arguments will be default to int.
K&R sysntax still gets suppot from the latest compilers for compatibility.In cases where code must be compilable by either standard-conforming or K&R C-based compilers, the STDC macro can be used to split the code into Standard and K&R sections to prevent the use on a K&R C-based compiler of features available only in Standard C.

main(argc, argv)
int argv[]; {
return 0;
}
The type of argc is int in K&R C and C90 due to the implicit integer conversion rule but it's not a conforming code in C99 & C11. Because the implicit int conversion has been deprecated in C99 and C11. Same goes for the return value of main().
main() receives the arguments passed from the host. Since main() can't receive array of ints but only an array of strings. This could potentially cause undefined behaviour because the actual arguments passed to main() can't be accessed with using an integer array. Compiler can't do type checking for the parameters because main() is called from outside (from the hosted environment). So compiler assumes whatever you say as parameters for main() are correct. You can even do:
int main(argc, argv, a, b,c)
int argc;
int argv[];
int a, b, c;
{
....
}
This is a valid code. But there's no legal way to access all these ints (except argc).

GCC comes with a non-standard setup as default. The code you posted will not compile on a conforming C compiler.
Compile with a C compiler instead. gcc -std=c99 -pedantic-errors will not compile your code.

Related

Implicit declaration in C language

Consider the following quote from the C book by Dennis ritchie
All variables must be declared before use, although certain
declarations can be made implicitly by content.
It is known that all variables of any type must be declared before using it further. I am unaware with the latter part of the statement that certain declarations can be made implicitly
by content.
In C, in general, the variables fall under four basic data types char, int, float, double. How can a variable from these datatypes can be used without any declaration before. Please provide an example that shows implicit declaration based on content the variable holds.
By "certain declarations" the author means declaration of things which are not variables. At the time the book has been written C allowed implicit declaration of functions: the compiler simply assumed that the function returns integer. Modern C standards make such declarations illegal.
When the first edition of K&R was written, there was no C standard. When the second edition of K&R was written, the C89/C90 standard was about to be finalized. Because of the legacy from code written before C89 was finalized, the standard had to permit:
#include <stdio.h>
double sqrt();
main(argc, argv)
char **argv;
{
if (argc > 1)
printf("sqrt(%s) = %f\n", argv[1], sqrt((double)atoi(argv[1])));
else
printf("sqrt(%.0f) = %f\n", 2.0, sqrt(2.0));
return 0;
}
Note that the return type of main() is implicitly int; the function argument argc is implicitly int; the function atoi() has an implicit return type of int. Note too that the argument to sqrt() had to be explicitly a double value; the compiler could not automatically convert the argument type because prototypes were not a part of C before the C89 standard.
Such code is no longer acceptable to C99 or C11 compilers. You could use:
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
if (argc > 1)
printf("sqrt(%s) = %f\n", argv[1], sqrt(atoi(argv[1])));
else
printf("sqrt(%.0f) = %f\n", 2.0, sqrt(2));
return 0;
}
This uses the standard headers to declare the functions with complete prototypes, so it is no longer necessary to cast the argument to sqrt(). In C99 or C11, you could omit the return 0; and the effect would be the same. Personally, I don't like the loophole that allows that and continue to write the return explicitly. The return was necessary in C90 to send a determinate status to the environment (e.g. the shell the invoked the program).

Why the program compiles?

I am just trying to understand this C code ( not trying to achieve any functional goal by the program). This compiles using gcc.
Is this main in
main(int a, char *argv[] )
format? Is it permissible to declare anything beween argument and function body (similar to char *a; here)?
#include <stdio.h>
main(u,_,a)
char
*a;
{
//printf("%s\n",_,a);//just to help debugging
//printf("%d\n",u); //just to help debugging
}
This is an old, obsolete way of writing C functions.
In an ancestor language of C, there were no types: all variables contained a machine word. So a function definition would start like this:
main(u, _, a) {
/* ... some code ... */
}
C as it used to be, known as “K&R C” from the authors of the seminal book about C (Brian Kernighan and Dennis Ritchie) added types in a form that looked like variable declarations, and were between the list of function parameters and the code of the function.
int main(u, _, a)
int u;
int _;
char *a;
{
/* ... some code ... */
}
In K&R C, if a type is int, then in many places it can be omitted. For a function parameter, you can omit the type declaration line altogether.
int main(u, _, a)
char *a;
{
/* ... some code ... */
}
ANSI C was standardized in 1989, and one of its main innovations was function prototypes. In proper ANSI C, you declare all functions before use and you declare the types of all arguments.
int main(int u, int _, char *a)
{
/* ... some code ... */
}
C compilers still support the old form for legacy code. (If they conform to the 1989 C standard, they have to.) There isn't much legacy code left after more than 20 years, so you won't find such code often.
(Note that this is not the right type for main. I think Gcc will warn you about that but you may have to turn the warning settings up.)
Declarations between argument list and function body were part of the so called K&R C (the first version of C). So yes, they are valid, if your compiler can compile K&R code.
About main() having more than two arguments... yes, in fact, main can have up to three arguments:
int main (int argc, char *argv[], char *envp[]);
The third argument being an array of pointers to strings, containing each one of them a environment variable definition (a string in the form name=value)
That's an old declaration that nobody uses anymore except for obfuscation (see also: trigraphs!). I think it is illegal under the new C standards, but gcc still supports it for backward compatibility.
The way it works is the types are listed under the function, and the return type is left off. No return type means it defaults to int. The typical main function could be written this way:
main(argc, argv)
int argc;
char** argv;
{
printf("%d\n", argc);
return 0;
}
You cannot declare other variables before the opening brace. Try adding int c; and get this error:
test.c:4: error: declaration for parameter ‘c’ but no such parameter
This is an invalid form of main declaration. This is invalid in C99 / C11 but also invalid in C90.
(See 5.1.2.2.1 for valid declarations of main function in C90).

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.

Is this code valid under any C standard?

Does this code follow C standards (e.g. C89, C99, C10x)?
void
main(int a,int b, int c, int d,char *msg){
if(d==1){
printf("%s\n",msg);
}else{
main(1,2,3,1,&"Hello Stackoverflow");
}
}
If not, why?
There's one error: &"Hello Stackoverflow" does not have type char*, so you shouldn't pass that to a function expecting that type.
Apart from that, this program is allowed by the Standard as an implementation-specific extension, but a compiler has the freedom to decline it.
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.
(2011 Standard, latest draft section 5.1.2.2.1, emphasis added.)
There is no ban on recursive calls to main in the C Standard. This is a difference with C++, which does outlaw that.
You mean beside it won't run? main is defined to take int, char** as arguments.
Depending on the compiler, this either will fail to start up as the run-time can't find main(int, char**), or on older compilers it'll just crash because it piddles on the stack.
It's only valid under C99 and later if the implementation explicitly documents that main may take 5 parameters (4 int and 1 char *) and return void (that's the "or in some other implementation-defined manner" clause that larsmans referenced in his now-un-deleted answer, and I don't think that clause was present in C89).
Otherwise the behavior is undefined, meaning the compiler may or may not choke on it.

why "int main(anything_you_type)" doesnt produce any error?

Here I have written my name in main argument declaration but still this program works and did not give any warning.
#include <stdio.h>
int main(Mr32)
{
printf("why this works?");
return 0;
}
Whenever I write anything in place of mr32 , The code still works. I really don't know why this is happening. As per C programming standard this is wrong, right?
Edit : I have tried -Wall but it does not give any warning.
I think here it should be error, because i am not doing as standard C function definition declaration
In c every function definition must follow this format
return-type function_name ( arg_type arg1, ..., arg_type argN );
This should also appy to main() right ..??
Okay -Wextra shows warning that mr32 is by default int.
Then why is the default type of any argument in main() an int?
In the K&R C definition a parameter without type defaults to int. Your code then corresponds to
int main( int Mr32 ) {
printf("why this works?");
return 0;
}
Take a look at this answer for the details: C function syntax, parameter types declared after parameter list
Update
To summarize: in C89 K&R declarations are still supported
undeclared parameter types default to int
void foo( param )
defaults to
void foo( int param )
unspecified return types default to int
foo()
defaults to
int foo()
Note
Although this is supported I would never use it: code should be readable
Obviously you are using a rather lax compiler. This is what the standards king Comeau makes of it:
Comeau C/C++ 4.3.10.1 (Oct 6 2008 11:28:09) for ONLINE_EVALUATION_BETA2
Copyright 1988-2008 Comeau Computing. All rights reserved.
MODE:strict errors C99
"ComeauTest.c", line 2: error: standard requires that parameter "Mr32" be given a
type by a subsequent declaration ("int" assumed)
int main(Mr32)
^
1 error detected in the compilation of "ComeauTest.c".
In strict mode, with -tused, Compile failed
Hit the Back Button to review your code and compile options.
Compiled with C++0x extensions enabled.
As to what your compiler is doing that's hard to say since you didn't say what your compiler is.
You say you wish to adhere to C89. In that case a parameter with no type information is assumed to have type int. Your main function is interpreted like this:
int main(int Mr32)
Of course this is still not valid C. Valid main functions in C are:
int main(void)
int main(int argc, char* argv[])
Since this appears to be code for a hosted program, the code is not valid C, unless the specific compiler has documented the behavior of "Mr32".
To have a main() function that accepts other parameters than (void) or (int argc, char *argv[]) is implementation-defined behavior (C99 5.1.2.2.1). So if there isn't any documentation about what "Mr32", is supposed to do, the compiler does not follow the standard. Or more specifically, there needs to be documentation of what the int main(int) syntax is supposed to do on this compiler.
This is true regardless of K&R style function parameters. I believe the standard is the same for C89, C99 as well as all C++ standards.
According to the foot note 9) in the standard, it is acceptable to have another int not named argc, or a typedef equivalent to an int. But in that case there must be a second parameter of type char** as well, which isn't the case here.

Resources