Related
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.
In this example i'm getting a Conflicting types error as expected:
#include <stdio.h>
int a(int b);
int a(int *b){
return 6;
}
int main(){
return 0;
}
But not in this example:
#include <stdio.h>
int a(int b);
int a(){
return 6;
}
int main(){
return 0;
}
Why the second example is compiling fine although the declaration and definition and of a are still different?
Overview and History
Due to the history of how the C language developed, int a() does not mean “a takes no arguments and returns an int.” It means “a takes unspecified arguments and returns an int.”
Since “unspecified arguments” is nominally compatible with “one argument that is an int,” the compiler does not give an error for conflicting types. Due to further rules in C (see “Function Compatibility” below), the types are incompatible, but the compiler is not required to diagnose this.
Originally in C, functions were declared with a parameter list of (), and it was up to the caller to provide the correct types. (In addition, arguments were “promoted”; char arguments were converted to int, and so on, but this is a separate issue.) Where a function was defined, it was defined with names of parameters, such as int a(b), and the declarations of those parameters followed, as in:
int a()
int b;
{
return 6*b;
}
But that was only for the definition. The declaration did not have those declarations of the parameter types.
Later, to improve the type information about functions, C added grammar for full declarations of functions including parameter types, such as int a(int b). However, since the old grammar was already using int a() to mean “unspecified parameters,” the language had to keep that meaning to support old code.
Instead, a special form was designated to mean “no parameters,” and that is to put void by itself in the parameter list. int a(void) means “a is a function taking no parameters and returning int.” So, if you declare a function as int a(void); and then define it with int a(int b) { … }, the compiler will give you an error message.
Function Compatibility
One of the rules for function types to be compatible in C 2018 6.7.6.3 15 says:
… If one type has a parameter type list and the other type is specified by a function definition that contains a (possibly empty) identifier list, both shall agree in the number of parameters,…
The declaration int a(int b); has a parameter type list with one parameter.
This definition:
int a(){
return 6;
}
has an empty identifier list and, between the int a() and the {, defines no parameters. So they do not agree in the number of parameters. However, the compiler is not required to diagnose this incompatibility.
Because in C (but not C++), a() declares a function with an unspecified number of parameters. Use a(void) instead.
See C function with no parameters behavior
Second example:
int a(){
a is a function taking unspecified number of parameters. So any number is fine and thus no error.
It is a compiler defect.
According to the C Standard (6.7.6.3 Function declarators (including prototypes))
...If one type has a parameter type list and the other type is specified
by a function definition that contains a (possibly empty) identifier
list, both shall agree in the number of parameters, and the type of
each prototype parameter shall be compatible with the type that
results from the application of the default argument promotions to the
type of the corresponding identifier
So as in these declarations
int a(int b);
int a(){
return 6;
}
the number of parameters differs for the functions the compiler shall issue a message because the name a is used to declare two different functions.
For example running this code using gcc 8.3 you can get the following errors
prog.c: In function ‘a’:
prog.c:5:1: error: number of arguments doesn’t match prototype
int a(){
^~~
prog.c:3:5: error: prototype declaration
int a(int b);
^
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.
The C standard specifies two forms of definition for main for a
hosted implementation:
int main(void) { /* ... */ }
and
int main(int argc, char *argv[]) { /* ... */ }
It may be defined in ways that are "equivalent" to the above (for
example, you can change the parameter names, replace int by a typedef
name defined as int, or write char *argv[] as char **argv).
It may also be defined "in some other implementation-defined manner"
-- which means that things like int main(int argc, char *argv[],
char *envp) are valid if the implementation documents them.
The "in some other implementation-defined manner" clause was not in
the 1989/1990 standard; it was added by the 1999 standard (but the
earlier standard permitted extensions, so an implementation could
still permit other forms).
My question is this: Given the current (2011) ISO C standard, is a
definition of the form
int main() { /* ... */ }
valid and portable for all hosted implementations?
(Note that I am not addressing either void main or the use of
int main() without parentheses in C++. This is just about the
distinction between int main(void) and int main() in ISO C.)
No.
According to the normative wording of the standard, a definition
using empty parentheses without the void keyword is not one of the
forms that must be accepted, and strictly speaking the behavior of
such a program is undefined.
Reference:
N1570
section 5.1.2.2.1. (The published 2011 ISO C standard, which is not
freely available, has the same wording as the N1570 draft.)
Paragraph 1 says:
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.
The use of the word "shall" outside a constraint means that any
program that violates it has undefined behavior. So if, for example, I write:
double main(unsigned long ocelots) { return ocelots / 3.14159; }
a conforming compiler isn't required to print a diagnostic, but it's
also not required either to compile the program or, if it does compile
it, to have it behave in any particular manner.
If int main() were equivalent to int main(void), then it
would be valid and portable to any conforming hosted implementation.
But it's not equivalent.
int main(void) { }
provides both a declaration (in this case, a prototype) and a
definition. The declaration, by using the void keyword, specifies that the function has no parameters. The definition specifies the same thing.
If I instead write:
int main() { }
then I'm using an old-style declaration and definition. (Such
declarations and definitions are obsolescent, but they're still
part of the language definition, and all conforming compilers must
still support them.)
As a declaration, it doesn't specify the number or type(s) of arguments
expected by the function. As a definition, it defines no parameters,
but compilers needn't use that information to diagnose incorrect calls.
DR #317 includes the C standard committee's 2006 ruling that a definition with () does not provide a prototype equivalent to one with (void) (thanks to hvd for finding that reference).
C allows main to be called recursively. Suppose I write:
int main(void) {
if (0) {
main(42);
}
}
The visible prototype int main(void) specifies that main takes
no arguments. A call that attempts to pass one or more arguments
violates a constraint, requiring a compile-time diagnostic.
Or suppose I write:
int main() {
if (0) {
main(42);
}
}
If the call main(42) were executed, it would have undefined behavior
-- but it doesn't violate a constraint, and no diagnostic is required.
Since it's protected by if (0), the call never happens, and
the undefined behavior never actually occurs. If we assume that
int main() is valid, then this program must be accepted by any
conforming compiler. But because of that, it demonstrates that
int main() is not equivalent to int main(void), and therefore
is not covered by 5.1.2.2.1.
Conclusion: Following the wording of the standard, an
implementation is permitted to document that int main() { } is
permitted. If it doesn't document it, it's still permitted to accept
it without complaint. But a conforming compiler may also reject
int main() { }, because it is not one of the forms permitted by
the standard, and its behavior is therefore undefined.
But there's still an open question: Was that the intent of the authors
of the standard?
Prior to the publication of the 1989 ANSI C standard, the void
keyword did not exist. Pre-ANSI (K&R) C programs would define main
either as
main()
or as
int main()
A major goal of the ANSI standard was to add new features (including
prototypes) without breaking existing pre-ANSI code. Stating that
int main() is no longer valid would have violated that goal.
My suspicion is that the authors of the C standard did not intend
to make int main() invalid. But the standard as written does not
reflect that intent; it at least permits a conforming C compiler
to reject int main().
Practically speaking, you can almost certainly get away with it.
Every C compiler I've ever tried will accept
int main() { return 0; }
without complaint, with behavior equivalent to
int main(void) { return 0; }
But for a variety of reasons:
Following both the letter and the intent of the standard;
Avoiding the use of an obsolescent feature (a future standard could remove old-style function definitions);
Maintaining good coding habits (the difference between () and (void) is important for functions other than main that are actually called by other functions).
I recommend always writing int main(void) rather than int main().
It states the intent more clearly, and you can be 100% sure that your
compiler will accept it, rather than 99.9%.
A strong indication that int main() is meant to be valid, regardless of whether the standard accurately gives the wording to make it valid, is the fact that int main() is occasionally used in the standard without anyone raising any objection. While examples are not normative, they do indicate intent.
6.5.3.4 The sizeof and _Alignof operators
8 EXAMPLE 3 In this example, the size of a variable length array is computed and returned from a function:
#include <stddef.h>
size_t fsize3(int n)
{
char b[n+3]; // variable length array
return sizeof b; // execution time sizeof
}
int main()
{
size_t size;
size = fsize3(10); // fsize3 returns 13
return 0;
}
6.7.6.3 Function declarators (including prototypes)
20 EXAMPLE 4 The following prototype has a variably modified parameter.
void addscalar(int n, int m,
double a[n][n*m+300], double x);
int main()
{
double b[4][308];
addscalar(4, 2, b, 2.17);
return 0;
}
void addscalar(int n, int m,
double a[n][n*m+300], double x)
{
for (int i = 0; i < n; i++)
for (int j = 0, k = n*m+300; j < k; j++)
// a is a pointer to a VLA with n*m+300 elements
a[i][j] += x;
}
As for the actual normative text of the standard, I think too much is being read into "equivalent". It should be pretty clear that
int main (int argc, char *argv[]) {
(void) argc; (void) argv;
return 0;
}
is valid, and that
int main (int x, char *y[]) {
(void) argc; (void) argv;
return 0;
}
is invalid. Nonetheless, the standard explicitly states in the normative text that any names may be used, meaning that int main (int argc, char *argv[]) and int main (int x, char *y[]) count as equivalent for the purposes of 5.1.2.2.1. The strict English meaning of the word "equivalent" is not how it is meant to be read.
A somewhat looser interpretation of the word is what Keith Thompson suggests in his answer.
An equally valid even looser interpretation of the word does allow int main(): both int main(void) and int main() define main as a function returning int and taking no parameters.
Neither the standard nor any official DRs currently answer the question of which interpretation is intended, so the question is unanswerable, but the examples strongly suggest that last interpretation.
Yes.
int main() { /* ... */ }
is equivalent to
int main(void) { /* ... */ }
N1570 5.1.2.2.1/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.
6.7.6.3/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.
(emphasis mine)
As is clearly stated by the standard, the definition int main() { /* ... */ } does specify that the funtion main has no parameters. And it is clear to all of us, that this function definition does specify that the return type of the function main is int. And, since 5.1.2.2.1 does not require the declaration of main to have a prototype, we can safely affirm that the definition int main() { /* ... */ } satisfies all the requirement imposed by the standard (It [the main funtion] shall be defined with a return type of int and with no parameters, or [some other forms] .).
Nonetheless you should never use int main() {} in your code, because "The use of function declarators with empty parentheses (not prototype-format parameter type declarators) is an obsolescent feature." (6.11.6), and because this form of definition does not include a function prototype declarator, the compiler won't check whether the number and types of arguments are correct.
N1570 6.5.2.2/8
No other conversions are performed implicitly; in particular, the number and types of
arguments are not compared with those of the parameters in a function definition that
does not include a function prototype declarator.
(emphasis mine)
This question already has answers here:
Is there a difference between foo(void) and foo() in C++ or C?
(4 answers)
func() vs func(void) in C99
(4 answers)
Closed 5 years ago.
What is better: void foo() or void foo(void)?
With void it looks ugly and inconsistent, but I've been told that it is good. Is this true?
Edit: I know some old compilers do weird things, but if I'm using just GCC, is void foo() Ok? Will foo(bar); then be accepted?
void foo(void);
That is the correct way to say "no parameters" in C, and it also works in C++.
But:
void foo();
Means different things in C and C++! In C it means "could take any number of parameters of unknown types", and in C++ it means the same as foo(void).
Variable argument list functions are inherently un-typesafe and should be avoided where possible.
There are two ways for specifying parameters in C. One is using an identifier list, and the other is using a parameter type list. The identifier list can be omitted, but the type list can not. So, to say that one function takes no arguments in a function definition you do this with an (omitted) identifier list
void f() {
/* do something ... */
}
And this with a parameter type list:
void f(void) {
/* do something ... */
}
If in a parameter type list the only one parameter type is void (it must have no name then), then that means the function takes no arguments. But those two ways of defining a function have a difference regarding what they declare.
Identifier lists
The first defines that the function takes a specific number of arguments, but neither the count is communicated nor the types of what is needed - as with all function declarations that use identifier lists. So the caller has to know the types and the count precisely before-hand. So if the caller calls the function giving it some argument, the behavior is undefined. The stack could become corrupted for example, because the called function expects a different layout when it gains control.
Using identifier lists in function parameters is deprecated. It was used in old days and is still present in lots of production code. They can cause severe danger because of those argument promotions (if the promoted argument type do not match the parameter type of the function definition, behavior is undefined either!) and are much less safe, of course. So always use the void thingy for functions without parameters, in both only-declarations and definitions of functions.
Parameter type list
The second one defines that the function takes zero arguments and also communicates that - like with all cases where the function is declared using a parameter type list, which is called a prototype. If the caller calls the function and gives it some argument, that is an error and the compiler spits out an appropriate error.
The second way of declaring a function has plenty of benefits. One of course is that amount and types of parameters are checked. Another difference is that because the compiler knows the parameter types, it can apply implicit conversions of the arguments to the type of the parameters. If no parameter type list is present, that can't be done, and arguments are converted to promoted types (that is called the default argument promotion). char will become int, for example, while float will become double.
Composite type for functions
By the way, if a file contains both an omitted identifier list and a parameter type list, the parameter type list "wins". The type of the function at the end contains a prototype:
void f();
void f(int a) {
printf("%d", a);
}
// f has now a prototype.
That is because both declarations do not say anything contradictory. The second, however, had something to say in addition. Which is that one argument is accepted. The same can be done in reverse
void f(a)
int a;
{
printf("%d", a);
}
void f(int);
The first defines a function using an identifier list, while the second then provides a prototype for it, using a declaration containing a parameter type list.
void foo(void) is better because it explicitly says: no parameters allowed.
void foo() means you could (under some compilers) send parameters, at least if this is the declaration of your function rather than its definition.
C99 quotes
This answer aims to quote and explain the relevant parts of the C99 N1256 standard draft.
Definition of declarator
The term declarator will come up a lot, so let's understand it.
From the language grammar, we find that the following underline characters are declarators:
int f(int x, int y);
^^^^^^^^^^^^^^^
int f(int x, int y) { return x + y; }
^^^^^^^^^^^^^^^
int f();
^^^
int f(x, y) int x; int y; { return x + y; }
^^^^^^^
Declarators are part of both function declarations and definitions.
There are 2 types of declarators:
parameter type list
identifier list
Parameter type list
Declarations look like:
int f(int x, int y);
Definitions look like:
int f(int x, int y) { return x + y; }
It is called parameter type list because we must give the type of each parameter.
Identifier list
Definitions look like:
int f(x, y)
int x;
int y;
{ return x + y; }
Declarations look like:
int g();
We cannot declare a function with a non-empty identifier list:
int g(x, y);
because 6.7.5.3 "Function declarators (including prototypes)" says:
3 An identifier list in a function declarator that is not part of a definition of that function shall be empty.
It is called identifier list because we only give the identifiers x and y on f(x, y), types come after.
This is an older method, and shouldn't be used anymore. 6.11.6 Function declarators says:
1 The use of function declarators with empty parentheses (not prototype-format parameter type declarators) is an obsolescent feature.
and the Introduction explains what is an obsolescent feature:
Certain features are obsolescent, which means that they may be considered for
withdrawal in future revisions of this International Standard. They are retained because
of their widespread use, but their use in new implementations (for implementation
features) or new programs (for language [6.11] or library features [7.26]) is discouraged
f() vs f(void) for declarations
When you write just:
void f();
it is necessarily an identifier list declaration, because 6.7.5 "Declarators" says defines the grammar as:
direct-declarator:
[...]
direct-declarator ( parameter-type-list )
direct-declarator ( identifier-list_opt )
so only the identifier-list version can be empty because it is optional (_opt).
direct-declarator is the only grammar node that defines the parenthesis (...) part of the declarator.
So how do we disambiguate and use the better parameter type list without parameters? 6.7.5.3 Function declarators (including prototypes) says:
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.
So:
void f(void);
is the way.
This is a magic syntax explicitly allowed, since we cannot use a void type argument in any other way:
void f(void v);
void f(int i, void);
void f(void, int);
What can happen if I use an f() declaration?
Maybe the code will compile just fine: 6.7.5.3 Function declarators (including prototypes):
14 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.
So you can get away with:
void f();
void f(int x) {}
Other times, UB can creep up (and if you are lucky the compiler will tell you), and you will have a hard time figuring out why:
void f();
void f(float x) {}
See: Why does an empty declaration work for definitions with int arguments but not for float arguments?
f() and f(void) for definitions
f() {}
vs
f(void) {}
are similar, but not identical.
6.7.5.3 Function declarators (including prototypes) says:
14 An empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters.
which looks similar to the description of f(void).
But still... it seems that:
int f() { return 0; }
int main(void) { f(1); }
is conforming undefined behavior, while:
int f(void) { return 0; }
int main(void) { f(1); }
is non conforming as discussed at: Why does gcc allow arguments to be passed to a function defined to be with no arguments?
TODO understand exactly why. Has to do with being a prototype or not. Define prototype.
Besides syntactical differences, many people also prefer using void function(void) for pracitical reasons:
If you're using the search function and want to find the implementation of the function, you can search for function(void), and it will return the prototype as well as the implementation.
If you omit the void, you have to search for function() and will therefore also find all function calls, making it more difficult to find the actual implementation.
In C++, there is no difference in main() and main(void).
But in C, main() will be called with any number of parameters.
Example:
main (){
main(10, "abc", 12.28);
// Works fine!
// It won't give the error. The code will compile successfully.
// (May cause a segmentation fault when run)
}
main(void) will be called without any parameters. If we try to pass it then this ends up leading to a compiler error.
Example:
main (void) {
main(10, "abc", 12.13);
// This throws "error: too many arguments to function ‘main’ "
}