I'm trying to understand declarations, definitions and prototypes. I came across the excellent post https://stackoverflow.com/a/41805712/1825603. I do, however, need some clarification, but because I do not have enough reputation to comment directly to the post, I will ask here...
The relevant section:
In definitions
void func1() { } // obsolescent
and
void func2(void) { }
The former declares and defines a function func1
that has no parameters and no prototype
The latter declares and defines a function func2 with a prototype that
has no parameters.
When I see int main(void) { } as one of the Standard definitions for main in C99 5.1.2.2.1, I interpret from the above that it's "a declaration and definition of a function with a prototype that has no parameters". My confusion lies with C99 5.1.2.2.1, where it says, "The implementation declares no prototype for this function." By adding the void to int main() { }, does this mean the user-level code is declaring a prototype because the implementation hasn't? And if it's not a prototype, what is the effect of adding void?
Note: I believe I understand the reason the declaration int main(void); isn't used, ie, Declare main prototype, but don't think my question is a duplicate of this.
C 2018 6.2.1 2 says:
… ((A function prototype is a declaration of a function that declares the types of its parameters.)
Thus int main(int argc, char *argv[]); is a function prototype, because it declares the types of its parameters, argc and argv.
int main(int argc, char *argv[]) {} is also a function prototype. Even thought it is a function definition, it also declares the function.
Functions can be defined with an old style that did not have declarations in the parameter list, such as:
int main(argc, argv)
int argc;
char *argv[];
{
}
Although the types of the parameters are declared in the declaration list between the function declarator and the body of the function, this is not what the C standard means by declaring the types of the parameters. This phrasing in the C standard is unfortunately imprecise, but the intent is that a “function prototype” is a declaration of the modern form with the types specified in the parameter list, contrasted with the legacy form with only the parameter names in the list.
We can see this because C 2018 6.2.7 3 distinguishes a function prototype as a function declared with a parameter type list rather than a simple identifier list:
… a function type with a parameter type list (a function prototype)…
Also note the special form (void), as in int foo(void), counts as a function prototype as a special case; it is the modern form of declaration that asserts the function has no parameters. The old form int foo(); does not specify whether the function has parameters or not.
Is int main(void) { } a prototype?
Yes.
int main(void) { } is a function declaration and definition. As a declaration, it says nothing about the parameters. As a definition, it takes no parameters: i.e void.
Related
This question already has answers here:
What should main() return in C and C++?
(19 answers)
Closed 5 years ago.
My only exposure to programming has been Java,where I have not encountered (up to now) different conventions for writing the main method.I have been following to sources for learning c (K&R AND C Programming A Modern Approach) where they use very different forms of the main method (function).
K&R version up to now:
main() {
blah blah blah;
}
C Programming A Modern Approach
int main() {
blah blah blah;
return 0;
}
OR
int main() {
blah blah blah;
//returns nothing
}
To make matters more confusing I have seen people do :
int main(void) {
blah blah blah;
}
while they either returned 0 or did not.
I don't in my very uneducated assumption think this is only a standards issue but maybe something a bit more conceptual or deep.
Could someone shed some light on this issue?
K&R style is outdated and isn't correct according to the C standard any more.
Valid signatures are
int main(void)
and
int main(int argc, char *argv[])
or, equivalent because an array type in a function is adjusted to a pointer type anyways:
int main(int argc, char **argv)
The signature
int main()
happens to be valid as well, because an empty argument list means any number of arguments, that aren't described *). AFAIK, this is subject to change, so don't write it this way. Writing void is how you express this function doesn't take arguments in C.
Implementations of C are free to provide other implementation-defined entry points. But the two I listed above are the only ones guaranteed by the standard.
C99 introduced a special rule for main() that states if the function doesn't return anything, a value of 0 is returned implicitly. So only in main, you can skip the return. My advice is: don't. It's just confusing. But this is an opinion.
*) note this is different in C++, where nothing between the parantheses indeed means: no arguments.
Pre-standardized versions of C (known as K&R C) had the concept of a default type of int if none was given. So in K&R this:
main() {
Is the same as:
int main() {
As for the difference between int main() and int main(void), an empty parameter list means the function takes an unspecified number of parameters while (void) as a parameter list means the function takes no parameters. The former is acceptable, but the latter is preferred as it is more explicit.
Regarding the use of the return statement, a function with a non-void return type must use return to return a value, except (starting with the C99 standard) for the main function. In the case of main, a missing return statement implies a return value of 0.
Because the implicit return 0 for main was added in C99, you'll see some code that explicitly returns and some that doesn't depending on which version of the standard the programmer is conforming to.
There are two standard signatures for main as of the latest C language standard:
int main( void ) // void indicates "takes no arguments"
and
int main( int argc, char *argv[] ) // or char **argv, it means the same thing in this context
The names argc and argv are arbitrary; you can use different names if you wish.
Implementations may provide additional valid signatures for main - check your compiler documentation.
If your program does not take any command line arguments, use the first form, otherwise use the second.
C function declaration and definition syntax has evolved a bit over time, which is why different references use different conventions.
Implicit Typing
First of all, C originally allowed for implicit int declarations - if the compiler saw a function definition or declaration without a type specifier, it assumed the function returned int:
foo(); // modern equivalent: int foo( void )
This was allowed up until the 1999 standard, although was considered bad style by most of us long before then.
The void keyword was not introduced until the 1989 standard. As a type specifier, it indicates a type with no values. As an identifier in a function parameter list, it indicates that the function takes no arguments.
Before the introduction of the void keyword, there was no good way (other than documentation) to distinguish between functions that returned a value you were meant to use vs. functions that just executed some action. Some of us used the "implicit int" convention to indicate those functions weren't meant to return anything meaningful:
foo(); /* returns int, but return value not meant to be used */
int bar(); /* returns int, return value meant to be used */
Again, this was just a convention, and far from universal. Now we'd use the void keyword:
void foo(); /* does not return a value */
int bar(); /* returns int */
Function Prototype Syntax
Originally, a function definition looked something like this:
foo( bar, bletch, blurga )
int bar;
double bletch;
char *blurga;
{
/* function body */
}
The parameter list only specified the names of the parameters, not their types; that was done in a separate set of declarations between the function declarator and the opening { of the function body. A function that took no arguments had an empty identifier list in the function definition:
blah( )
{
/* function body */
}
Function declarations only specified the name and return type of the function; it didn't specify the parameters at all:
foo( ); /* no bar, bletch, or blurga */
An empty identifier list in a function declaration indicates that the function takes an unspecified number of arguments, not zero arguments. The compiler could check that the return type of the function call was being used correctly, but it could not check that the number and types of parameters in the call were correct.
The 1989 language standard introduced the concept of function prototype syntax, where the type of each parameter was specified along with its name in the parameter list:
foo( int bar, double bletch, char *blurga )
{
/* function body */
}
This applied to both the function declaration and definition:
foo( int bar, double bletch, char *blurga );
This change allowed the compiler to check that the number and types of parameters in a function call were correct, along with the return type. In addition, the void keyword could be used in the parameter list to indicate that the function took no parameters, in both the definition and declaration:
blah( void ); /* declaration, returns int, takes no parameters */
blah( void ) /* definition */
{
/* function body */
}
So yeah, depending on which language revision you're working against, main would be written differently:
K&R:
main() main( argc, argv )
{ int argc;
... char *argv[];
} {
...
}
C89:
main( void ) main( int argc, char *argv[] )
{ {
... ...
} }
C99 and later:
int main( void ) int main( int argc, char *argv[] )
{ {
... ...
} }
C standard defines signature for main either as
int main(void)
or
int main(int argc, char *argv[])
Adding return 0; as a last statement in main function is optional.
Standard also says about some implementation defined prototype. int main() is accepted by GCC compiler.
main() is an old school prototype and almost deprecated.
This question already has answers here:
Non-standard signature of main() compiles successfully
(4 answers)
Closed 9 years ago.
5.1.2.2.1 Program startup
The implementation declares no prototype for this function. It shall be defined
with a return type of int and with no parameters.
I have defined like this,
int main(int a, int b, int c){.......}
It works. I didn't understood the first line "The implementation declares no prototype for this function"
Need help, Thanks
All it means is that main is not declared in advance. There's no line like
int main(int argc, char*argv[]);
and that means that when you define the function, you can pretend it takes any arguments and returns any type you like without getting a compiler error.
Of course, main is called by the operating system, so it will expect your definition to match whatever convention it uses for passing parameters. In practice, except on embedded systems, your definiton for main has to match the above.
When you are making a prototype then it means that you want to call it elsewhere which is not the case for main function.
From the docs:-
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.
declaration or prototype is not require for main function
functions other than main requires declaration and
definition
int sum(int,int); //declaration
int sum(int a,int b) //definition
{
//body
}
You left out the rest of the quote from that section of the standard, I am going to quote the C99 draft standard which says:
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.
The shall be defined is the quote is the important part, it says it must follow one of these two signatures or if available some implementation specific signature which would be defined by the compiler implementor.
If I attempt to build this in the latest version of clang I see the following errors:
error: second parameter of 'main' (argument array) must be of type 'char **'
int main(int a, int b, int c){}
error: third parameter of 'main' (environment) must be of type 'char **'
6.7.6.3 Function declarators (including prototypes)
This part of the standard deals with 'Identifier list' and 'Parameter type list'.
First of all, function declaration (not definition) is same as the function prototype. Am I correct? If this is right, then why the standard says 'including prototypes'?
I am unable to understand the difference between 'Identifier list' and 'Parameter type list' with respect to function declaration.
int fun(); // Declaration
int fun(int x)// Definition, but the signature doesn't match and it works.
{ return x; }
Can someone explain, I am confused?
Function declaration is not the same as function prototype. Prototype is a special kind of declaration. For example, this is a function declaration that is not a prototype
int foo();
And the following declarations are prototypes
int foo(int a, double b);
int bar(char, float);
float baz(void);
I.e. prototype is a declaration that describes the number and the types of function parameters. A non-prototype declaration does not say anything about parameters.
Now, C language still supports old K&R-style function definitions in addition to "modern" function definitions. K&R-style function definition looks as follows
int foo(a, b)
int a;
double b;
{
...
}
A "modern" function definition looks as follows
int foo(int a, double b)
{
...
}
As you can see, the K&R-style parameter list is just a, b. It includes parameter names, but does not include their types. This is what the grammar refers to as identifier-list. The "modern" parameter list is int a, double b and this is what the grammar refers to as parameter-type-list.
I.e. identifier-list is a part of K&R-style function definition syntax, while parameter-type-list is a part of "modern" function definition syntax.
Note also that in C language the declaration
int foo();
does not mean that foo takes no arguments. It means that foo take an unspecified number of arguments, i.e. it simply turns off argument type checking, argument number checking and argument conversions for foo at the point of the call. Such "signature" will match a definition for foo with any parameter list. This
int foo(int x)
{
...
}
is a perfectly valid definition for foo declared as shown above. The fact that it is declared with () simply means that the compiler will not verify the arguments at the point of the call. It will be your responsibility to make sure that you are calling foo with exactly one argument of int type.
In C11 standard
6.7.6.3 Function declarators (including prototypes)
Constraints
D( parameter-type-list )
or
D( identifier-listopt )
While declaring function you need not give identifiers list. BUt you should at least mention type list
example:
int sum(int,int); //declaration
int sum(int a,int b); //declaration
both are declaration of same function .
but second one you also mentioned identifiers that is optional.
C11(ISO/IEC 9899:201x) §6.2.1 Scopes of identifiers Section 2
A function prototype is a declaration of a function that declares the types of its parameters.
As of your example, for the function definition
int fun(int x)
{ return x; }
Both int func(int x); and int func(); are valid function declarations. But only the former is a function prototype.
You can even omit the variable names in function declarations, e.g, int func(int);. Although we usually prefer not to do it because of lack of readability.
What is the correct way, according to the latest C standard, to define functions without parameters: int main() or int main(void)?
Both forms of definition are valid (the one without void is an invalid prototype and an incomplete (albeit valid) declaration).
The form int main(void) { /* whetever */ } also provides a prototype for the function.
The form int main() { /* whatever */ } does not provide a prototype (and the compiler cannot check if it is called correctly).
See the Standard (PDF)
6.7.5.3/14
An empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters.
difference between definition: int main() { /* whatever */ }
and declaration: int main();
and prototype: int main(void);.
The definition does not provide a prototype;
the declaration is valid but specifies no information about the number or types of parameters;
the prototype is ok and compatible with the definition.
I have a library I created,
File mylib.c:
#include <mylib.h>
int
testlib() {
printf("Hello, World!\n");
return (0);
}
File mylib.h:
#include <stdio.h>
extern int testlib();
In my program, I've attempted to call this library function:
File myprogram.c:
#include <mylib.h>
int
main (int argc, char *argv[]) {
testlib();
return (0);
}
When I attempt to compile this program I get the following error:
In file included from myprogram.c:1
mylib.h:2 warning: function declaration isn't a prototype
I'm using: gcc (GCC) 3.4.5 20051201 (Red Hat 3.4.5-2)
What is the proper way to declare a function prototype?
In C int foo() and int foo(void) are different functions. int foo() accepts an arbitrary number of arguments, while int foo(void) accepts 0 arguments. In C++ they mean the same thing. I suggest that you use void consistently when you mean no arguments.
If you have a variable a, extern int a; is a way to tell the compiler that a is a symbol that might be present in a different translation unit (C compiler speak for source file), don't resolve it until link time. On the other hand, symbols which are function names are anyway resolved at link time. The meaning of a storage class specifier on a function (extern, static) only affects its visibility and extern is the default, so extern is actually unnecessary.
I suggest removing the extern, it is extraneous and is usually omitted.
Quick answer: change int testlib() to int testlib(void) to specify that the function takes no arguments.
A prototype is by definition a function declaration that specifies the type(s) of the function's argument(s).
A non-prototype function declaration like
int foo();
is an old-style declaration that does not specify the number or types of arguments. (Prior to the 1989 ANSI C standard, this was the only kind of function declaration available in the language.) You can call such a function with any arbitrary number of arguments, and the compiler isn't required to complain -- but if the call is inconsistent with the definition, your program has undefined behavior.
For a function that takes one or more arguments, you can specify the type of each argument in the declaration:
int bar(int x, double y);
Functions with no arguments are a special case. Logically, empty parentheses would have been a good way to specify that a function takes no arguments, but that syntax was already in use for old-style function declarations, so the ANSI C committee invented a new syntax using the void keyword:
int foo(void); /* foo takes no arguments */
A function definition (which includes code for what the function actually does) also provides a declaration. In your case, you have something similar to:
int testlib()
{
/* code that implements testlib */
}
This provides a non-prototype declaration for testlib. As a definition, this tells the compiler that testlib has no parameters, but as a declaration, it only tells the compiler that testlib takes some unspecified but fixed number and type(s) of arguments.
If you change () to (void) the declaration becomes a prototype.
The advantage of a prototype is that if you accidentally call testlib with one or more arguments, the compiler will diagnose the error.
(C++ has slightly different rules. C++ doesn't have old-style function declarations, and empty parentheses specifically mean that a function takes no arguments. C++ supports the (void) syntax for consistency with C. But unless you specifically need your code to compile both as C and as C++, you should probably use the () in C++ and the (void) syntax in C.)
Try:
extern int testlib(void);