Function Syntax in C - c

I'm pretty new to C, I've been studying someone else's code and I've found this function:
static
cp_file(output, input, record, ft)
dy_char *output; /* output file */
dy_char *input; /* input file */
dy_char *record; /* record id */
int ft; /* file type */
{
Does this do exactly the same thing as saying this:
static cp_file(dy_char *output, dy_char *input, dy_char *record, int ft) {
Is one more efficient than the other, or is it purely a different style of syntax? If they are different, what are the differences?

No, they are not identical.
The first form is the old-style function definition and the second is the prototype form of function definition.
They differ with respect to the argument passing conversion. Functions with prototype convert arguments as if by assignment while non-prototype functions like in your first example perform default argument promotion.
Arguments conversion for the old form:
(C99, 6.5.2.2p6) "If the expression that denotes the called function has a type that does not include a prototype, the integer promotions are performed on each argument, and arguments that have type float are promoted to double. These are called the default argument promotions."
Arguments conversion for the prototype form:
(C99, 6.5.2.2p7) "If the expression that denotes the called function has a type that does include a prototype, the arguments are implicitly converted, as if by assignment, to the types of the corresponding parameters, taking the type of each parameter to be the unqualified version of its declared type."
Note that the old form (non-prototype) is obsolescent and is strongly discouraged.
(C99, 6.11.7p1 Future languages directions) "The use of function definitions with separate parameter identifier and declaration lists (not prototype-format parameter type and identifier declarators) is an obsolescent feature."

Both are identical, However,
the latter is the standard conformant syntax, while the former is the obscure K&R syntax.
Always, use the standard conformant way when writing any new code, old code bases might use the K&R syntax as it was commonly used syntax at that time.

Yes, both statements are mostly identical except as noted by ouah. This is the "original" pre-ANSI syntax for declaring functions. It went into disuse in the early 1990's.

Related

Default argument promotions according to C standards

I was reading C standard for default argument promotions and got confused over many points. This question shows all the paragraphs that i have doubt on in a proper way.
First of all in Paragraph 6 point 3, it says if the prototype ends with ellipsis the behavior is undefined. Now my doubt is that if we talk about printf, it's prototype also ends with ellipsis but it's behavior is not undefined and in fact it follows the point 1 of paragraph 6. What the standard is trying to explain here? and further it says that if types of the arguments after promotion are not compatible with the types of the parameters, the behavior is undefined.. Now here my doubt is that if parameters are already declared in the function prototype why in first place arguments are getting promoted.
Than in paragraph 6 point 4,it says that the types of the arguments after promotion are not compatible with those of the parameters after promotion, the behavior is undefined. As here, it is mentioned that the function do not have a prototype, So exactly about what parameters they are talking about ? and how parameters get promoted. I have only studied about argument promotions.
Than in paragraph 7 point 1 what does this line mean : taking the type of each parameter to be the unqualified version of its declared type.
I am having really a very hard time understanding all this. It would be really helpful if you can explain all points with proper examples one by one. I am non native English speaker, if i am misunderstanding some standard's points, please point that mistakes too.
In C 1999 clause 6.5.2.2 paragraph 6, the item labeled 3 in that question is intended to be interpreted with the item labeled 1: If the calling expression use a type that does not have a prototype, and the called function is defined with a prototype that ends with an ellipsis or the promoted arguments types are incompatible with the parameter types, then the behavior is undefined.
So this is not saying you cannot use ellipsis, just that there can be a conflict between the function type used in an expression that calls a function and the function type used in defining the function.
Example:
File Caller.c contains:
void foo(); // No prototype (parameter types are not declared).
int main(void)
{
foo(3, 4);
}
File Function.c contains:
void foo(int x,...) // Prototype (parameter types are declared) and has ellipsis.
{
}
The behavior is undefined because foo is called as if it were void foo(), but it is defined with void foo(int x,...). This mismatch should not occur in modern practice, because declaring functions without prototypes is old-style. It is still supported in C so that old source code can still be compiled, but new source code should not use it. As long as parameter types are always declared, in both function declarations and function definitions, then this situation will never occur.
In paragraph 7, “taking the type of each parameter to be the unqualified versio of its declared type” means to ignore the qualifiers (const, volatile, restrict, or _Atomic). This means it is okay to pass an int argument for a const int parameter, and so on.

Unspecified parameters in function declaration [duplicate]

I've just come across someone's C code that I'm confused as to why it is compiling. There are two points I don't understand.
The function prototype has no parameters compared to the actual function definition.
The parameter in the function definition does not have a type.
#include <stdio.h>
int func();
int func(param)
{
return param;
}
int main()
{
int bla = func(10);
printf("%d", bla);
}
Why does this work?
I have tested it in a couple of compilers, and it works fine.
All the other answers are correct, but just for completion
A function is declared in the following manner:
return-type function-name(parameter-list,...) { body... }
return-type is the variable type that the function returns. This can not be an array type or a function type. If not given, then int
is assumed.
function-name is the name of the function.
parameter-list is the list of parameters that the function takes separated by commas. If no parameters are given, then the function
does not take any and should be defined with an empty set of
parenthesis or with the keyword void. If no variable type is in front
of a variable in the paramater list, then int is assumed. Arrays and
functions are not passed to functions, but are automatically converted
to pointers. If the list is terminated with an ellipsis (,...), then
there is no set number of parameters. Note: the header stdarg.h can be
used to access arguments when using an ellipsis.
And again for the sake of completeness. From C11 specification 6:11:6 (page: 179)
The use of function declarators with empty parentheses (not
prototype-format parameter type declarators) is an obsolescent
feature.
In C func() means that you can pass any number of arguments. If you want no arguments then you have to declare as func(void). The type you're passing to your function, if not specified defaults to int.
int func(); is an obsolescent function declaration from the days when there was no C standard, i.e. the days of K&R C (before 1989, the year the first "ANSI C" standard was published).
Remember that there were no prototypes in K&R C and the keyword void was not yet invented. All you could do was to tell the compiler about the return type of a function. The empty parameter list in K&R C means "an unspecified but fixed" number of arguments. Fixed means that you must call the function with the same number of args each time (as opposed to a variadic function like printf, where the number and type can vary for each call).
Many compilers will diagnose this construct; in particular gcc -Wstrict-prototypes will tell you "function declaration isn't a prototype", which is spot on, because it looks like a prototype (especially if you are poisoned by C++!), but isn't. It's an old style K&R C return type declaration.
Rule of thumb: Never leave an empty parameter list declaration empty, use int func(void) to be specific.
This turns the K&R return type declaration into a proper C89 prototype. Compilers are happy, developers are happy, static checkers are happy. Those mislead by^W^Wfond of C++ may cringe, though, because they need to type extra characters when they try to exercise their foreign language skills :-)
The empty parameter list means "any arguments", so the definition isn't wrong.
The missing type is assumed to be int.
I would consider any build that passes this to be lacking in configured warning/error level though, there's no point in being this allowing for actual code.
It's K&R style function declaration and definition. From C99 Standard (ISO/IEC 9899:TC3)
Section 6.7.5.3 Function Declarators (including prototypes)
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. (If both function types are "old style", parameter types are not compared.)
Section 6.11.6 Function declarators
The use of function declarators with empty parentheses (not prototype-format parameter
type declarators) is an obsolescent feature.
Section 6.11.7 Function definitions
The use of function definitions with separate parameter identifier and declaration lists
(not prototype-format parameter type and identifier declarators) is an obsolescent feature.
Which the old style means K&R style
Example:
Declaration: int old_style();
Definition:
int old_style(a, b)
int a;
int b;
{
/* something to do */
}
C assumes int if no type is given on function return type and parameter list. Only for this rule following weird things are possible.
A function definition looks like this.
int func(int param) { /* body */}
If its a prototype you write
int func(int param);
In prototype you can only specify the type of parameters. Parameters' name is not mandatory. So
int func(int);
Also if you dont specify parameter type but name int is assumed as type.
int func(param);
If you go farther, following works too.
func();
Compiler assumes int func() when you write func(). But dont put func() inside a function body. That'll be a function call
As stated #Krishnabhadra, all previous responses from other users, have a correct interpretation, and I just want to make a more detailed analysis of some points.
In the Old-C as in ANSI-C the "untyped formal parameter", take the dimencion of your work register or instruction depth capability (shadow registers or instruction cumulative cycle), in an 8bit MPU, will be an int16, in a 16bit MPU and so will be an int16 an so on, in the case 64bit architectures may choose to compile options like: -m32.
Although it seems simpler implementation at high level,
For pass multiple parameters, the work of the programmer in the control dimencion data type step, becomes more demanding.
In other cases, for some microprocessors architectures, the ANSI compilers customized, leveraged some of this old features to optimize the use of the code, forcing the location of these "untyped formal parameters" to work within or outside the work register, today you get almost the same with the use of "volatile" and "register".
But it should be noted that the most modern compilers,
not make any distinction between the two types of parameters declaration.
Examples of a compilation with gcc under linux:
 
In any case the statement of the prototype locally is of no use, because there is no call without parameters reference to this prototype will be remiss.
If you use the system with "untyped formal parameter", for an external call, proceed to generate a declarative prototype data type.
Like this:
int myfunc(int param);
Regarding parameter type, there are already correct answers here but if you want to hear it from the compiler you can try adding some flags (flags are almost always a good idea anyways).
compiling your program using gcc foo.c -Wextra I get:
foo.c: In function ‘func’:
foo.c:5:5: warning: type of ‘param’ defaults to ‘int’ [-Wmissing-parameter-type]
strangely -Wextra doesn't catch this for clang (it doesn't recognize -Wmissing-parameter-type for some reason, maybe for historical ones mentioned above) but -pedantic does:
foo.c:5:10: warning: parameter 'param' was not declared,
defaulting to type 'int' [-pedantic]
int func(param)
^
1 warning generated.
And for prototype issue as said again above int func() refers to arbitrary parameters unless you exclicitly define it as int func(void) which would then give you the errors as expected:
foo.c: In function ‘func’:
foo.c:6:1: error: number of arguments doesn’t match prototype
foo.c:3:5: error: prototype declaration
foo.c: In function ‘main’:
foo.c:12:5: error: too many arguments to function ‘func’
foo.c:5:5: note: declared here
or in clang as:
foo.c:5:5: error: conflicting types for 'func'
int func(param)
^
foo.c:3:5: note: previous declaration is here
int func(void);
^
foo.c:12:20: error: too many arguments to function call, expected 0, have 1
int bla = func(10);
~~~~ ^~
foo.c:3:1: note: 'func' declared here
int func(void);
^
2 errors generated.
If the function declaration has no parameters i.e. empty then it is taking unspecified number of arguments. If you want to make it take no arguments then change it to:
int func(void);
This is why I typically advise people to compile their code with:
cc -Wmissing-variable-declarations -Wstrict-variable-declarations -Wold-style-definition
These flags enforce a couple of things:
-Wmissing-variable-declarations: It is impossible to declare a non-static function without getting a prototype first. This makes it more likely that a prototype in a header file matches with the actual definition. Alternatively, it enforces that you add the static keyword to functions that don't need to be visible publicly.
-Wstrict-variable-declarations: The prototype must properly list the arguments.
-Wold-style-definition: The function definition itself must also properly list the arguments.
These flags are also used by default in a lot of Open Source projects. For example, FreeBSD has these flags enabled when building with WARNS=6 in your Makefile.
In the old-style declarator,
the identifier list must be absent unless
the declarator is used in the head of a function definition
(Par.A.10.1). No information about the types of the parameters is
supplied by the declaration. For example, the declaration
int f(), *fpi(), (*pfi)();
declares a function f returning an integer, a function fpi returning a pointer to an integer, >and a pointer pfi to a function returning an integer. In none of these are the parameter types >specified; they are old-style.
In the new-style declaration
int strcpy(char *dest, const char *source), rand(void);
strcpy is a
function returning int, with two arguments, the first a character
pointer, and the second a pointer to constant characters
SOURCE:- K&R book
I hope it cleared your doubt..

Why does this C code compile and link without error? [duplicate]

I've just come across someone's C code that I'm confused as to why it is compiling. There are two points I don't understand.
The function prototype has no parameters compared to the actual function definition.
The parameter in the function definition does not have a type.
#include <stdio.h>
int func();
int func(param)
{
return param;
}
int main()
{
int bla = func(10);
printf("%d", bla);
}
Why does this work?
I have tested it in a couple of compilers, and it works fine.
All the other answers are correct, but just for completion
A function is declared in the following manner:
return-type function-name(parameter-list,...) { body... }
return-type is the variable type that the function returns. This can not be an array type or a function type. If not given, then int
is assumed.
function-name is the name of the function.
parameter-list is the list of parameters that the function takes separated by commas. If no parameters are given, then the function
does not take any and should be defined with an empty set of
parenthesis or with the keyword void. If no variable type is in front
of a variable in the paramater list, then int is assumed. Arrays and
functions are not passed to functions, but are automatically converted
to pointers. If the list is terminated with an ellipsis (,...), then
there is no set number of parameters. Note: the header stdarg.h can be
used to access arguments when using an ellipsis.
And again for the sake of completeness. From C11 specification 6:11:6 (page: 179)
The use of function declarators with empty parentheses (not
prototype-format parameter type declarators) is an obsolescent
feature.
In C func() means that you can pass any number of arguments. If you want no arguments then you have to declare as func(void). The type you're passing to your function, if not specified defaults to int.
int func(); is an obsolescent function declaration from the days when there was no C standard, i.e. the days of K&R C (before 1989, the year the first "ANSI C" standard was published).
Remember that there were no prototypes in K&R C and the keyword void was not yet invented. All you could do was to tell the compiler about the return type of a function. The empty parameter list in K&R C means "an unspecified but fixed" number of arguments. Fixed means that you must call the function with the same number of args each time (as opposed to a variadic function like printf, where the number and type can vary for each call).
Many compilers will diagnose this construct; in particular gcc -Wstrict-prototypes will tell you "function declaration isn't a prototype", which is spot on, because it looks like a prototype (especially if you are poisoned by C++!), but isn't. It's an old style K&R C return type declaration.
Rule of thumb: Never leave an empty parameter list declaration empty, use int func(void) to be specific.
This turns the K&R return type declaration into a proper C89 prototype. Compilers are happy, developers are happy, static checkers are happy. Those mislead by^W^Wfond of C++ may cringe, though, because they need to type extra characters when they try to exercise their foreign language skills :-)
The empty parameter list means "any arguments", so the definition isn't wrong.
The missing type is assumed to be int.
I would consider any build that passes this to be lacking in configured warning/error level though, there's no point in being this allowing for actual code.
It's K&R style function declaration and definition. From C99 Standard (ISO/IEC 9899:TC3)
Section 6.7.5.3 Function Declarators (including prototypes)
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. (If both function types are "old style", parameter types are not compared.)
Section 6.11.6 Function declarators
The use of function declarators with empty parentheses (not prototype-format parameter
type declarators) is an obsolescent feature.
Section 6.11.7 Function definitions
The use of function definitions with separate parameter identifier and declaration lists
(not prototype-format parameter type and identifier declarators) is an obsolescent feature.
Which the old style means K&R style
Example:
Declaration: int old_style();
Definition:
int old_style(a, b)
int a;
int b;
{
/* something to do */
}
C assumes int if no type is given on function return type and parameter list. Only for this rule following weird things are possible.
A function definition looks like this.
int func(int param) { /* body */}
If its a prototype you write
int func(int param);
In prototype you can only specify the type of parameters. Parameters' name is not mandatory. So
int func(int);
Also if you dont specify parameter type but name int is assumed as type.
int func(param);
If you go farther, following works too.
func();
Compiler assumes int func() when you write func(). But dont put func() inside a function body. That'll be a function call
As stated #Krishnabhadra, all previous responses from other users, have a correct interpretation, and I just want to make a more detailed analysis of some points.
In the Old-C as in ANSI-C the "untyped formal parameter", take the dimencion of your work register or instruction depth capability (shadow registers or instruction cumulative cycle), in an 8bit MPU, will be an int16, in a 16bit MPU and so will be an int16 an so on, in the case 64bit architectures may choose to compile options like: -m32.
Although it seems simpler implementation at high level,
For pass multiple parameters, the work of the programmer in the control dimencion data type step, becomes more demanding.
In other cases, for some microprocessors architectures, the ANSI compilers customized, leveraged some of this old features to optimize the use of the code, forcing the location of these "untyped formal parameters" to work within or outside the work register, today you get almost the same with the use of "volatile" and "register".
But it should be noted that the most modern compilers,
not make any distinction between the two types of parameters declaration.
Examples of a compilation with gcc under linux:
 
In any case the statement of the prototype locally is of no use, because there is no call without parameters reference to this prototype will be remiss.
If you use the system with "untyped formal parameter", for an external call, proceed to generate a declarative prototype data type.
Like this:
int myfunc(int param);
Regarding parameter type, there are already correct answers here but if you want to hear it from the compiler you can try adding some flags (flags are almost always a good idea anyways).
compiling your program using gcc foo.c -Wextra I get:
foo.c: In function ‘func’:
foo.c:5:5: warning: type of ‘param’ defaults to ‘int’ [-Wmissing-parameter-type]
strangely -Wextra doesn't catch this for clang (it doesn't recognize -Wmissing-parameter-type for some reason, maybe for historical ones mentioned above) but -pedantic does:
foo.c:5:10: warning: parameter 'param' was not declared,
defaulting to type 'int' [-pedantic]
int func(param)
^
1 warning generated.
And for prototype issue as said again above int func() refers to arbitrary parameters unless you exclicitly define it as int func(void) which would then give you the errors as expected:
foo.c: In function ‘func’:
foo.c:6:1: error: number of arguments doesn’t match prototype
foo.c:3:5: error: prototype declaration
foo.c: In function ‘main’:
foo.c:12:5: error: too many arguments to function ‘func’
foo.c:5:5: note: declared here
or in clang as:
foo.c:5:5: error: conflicting types for 'func'
int func(param)
^
foo.c:3:5: note: previous declaration is here
int func(void);
^
foo.c:12:20: error: too many arguments to function call, expected 0, have 1
int bla = func(10);
~~~~ ^~
foo.c:3:1: note: 'func' declared here
int func(void);
^
2 errors generated.
If the function declaration has no parameters i.e. empty then it is taking unspecified number of arguments. If you want to make it take no arguments then change it to:
int func(void);
This is why I typically advise people to compile their code with:
cc -Wmissing-variable-declarations -Wstrict-variable-declarations -Wold-style-definition
These flags enforce a couple of things:
-Wmissing-variable-declarations: It is impossible to declare a non-static function without getting a prototype first. This makes it more likely that a prototype in a header file matches with the actual definition. Alternatively, it enforces that you add the static keyword to functions that don't need to be visible publicly.
-Wstrict-variable-declarations: The prototype must properly list the arguments.
-Wold-style-definition: The function definition itself must also properly list the arguments.
These flags are also used by default in a lot of Open Source projects. For example, FreeBSD has these flags enabled when building with WARNS=6 in your Makefile.
In the old-style declarator,
the identifier list must be absent unless
the declarator is used in the head of a function definition
(Par.A.10.1). No information about the types of the parameters is
supplied by the declaration. For example, the declaration
int f(), *fpi(), (*pfi)();
declares a function f returning an integer, a function fpi returning a pointer to an integer, >and a pointer pfi to a function returning an integer. In none of these are the parameter types >specified; they are old-style.
In the new-style declaration
int strcpy(char *dest, const char *source), rand(void);
strcpy is a
function returning int, with two arguments, the first a character
pointer, and the second a pointer to constant characters
SOURCE:- K&R book
I hope it cleared your doubt..

Why does a function with no parameters (compared to the actual function definition) compile?

I've just come across someone's C code that I'm confused as to why it is compiling. There are two points I don't understand.
The function prototype has no parameters compared to the actual function definition.
The parameter in the function definition does not have a type.
#include <stdio.h>
int func();
int func(param)
{
return param;
}
int main()
{
int bla = func(10);
printf("%d", bla);
}
Why does this work?
I have tested it in a couple of compilers, and it works fine.
All the other answers are correct, but just for completion
A function is declared in the following manner:
return-type function-name(parameter-list,...) { body... }
return-type is the variable type that the function returns. This can not be an array type or a function type. If not given, then int
is assumed.
function-name is the name of the function.
parameter-list is the list of parameters that the function takes separated by commas. If no parameters are given, then the function
does not take any and should be defined with an empty set of
parenthesis or with the keyword void. If no variable type is in front
of a variable in the paramater list, then int is assumed. Arrays and
functions are not passed to functions, but are automatically converted
to pointers. If the list is terminated with an ellipsis (,...), then
there is no set number of parameters. Note: the header stdarg.h can be
used to access arguments when using an ellipsis.
And again for the sake of completeness. From C11 specification 6:11:6 (page: 179)
The use of function declarators with empty parentheses (not
prototype-format parameter type declarators) is an obsolescent
feature.
In C func() means that you can pass any number of arguments. If you want no arguments then you have to declare as func(void). The type you're passing to your function, if not specified defaults to int.
int func(); is an obsolescent function declaration from the days when there was no C standard, i.e. the days of K&R C (before 1989, the year the first "ANSI C" standard was published).
Remember that there were no prototypes in K&R C and the keyword void was not yet invented. All you could do was to tell the compiler about the return type of a function. The empty parameter list in K&R C means "an unspecified but fixed" number of arguments. Fixed means that you must call the function with the same number of args each time (as opposed to a variadic function like printf, where the number and type can vary for each call).
Many compilers will diagnose this construct; in particular gcc -Wstrict-prototypes will tell you "function declaration isn't a prototype", which is spot on, because it looks like a prototype (especially if you are poisoned by C++!), but isn't. It's an old style K&R C return type declaration.
Rule of thumb: Never leave an empty parameter list declaration empty, use int func(void) to be specific.
This turns the K&R return type declaration into a proper C89 prototype. Compilers are happy, developers are happy, static checkers are happy. Those mislead by^W^Wfond of C++ may cringe, though, because they need to type extra characters when they try to exercise their foreign language skills :-)
The empty parameter list means "any arguments", so the definition isn't wrong.
The missing type is assumed to be int.
I would consider any build that passes this to be lacking in configured warning/error level though, there's no point in being this allowing for actual code.
It's K&R style function declaration and definition. From C99 Standard (ISO/IEC 9899:TC3)
Section 6.7.5.3 Function Declarators (including prototypes)
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. (If both function types are "old style", parameter types are not compared.)
Section 6.11.6 Function declarators
The use of function declarators with empty parentheses (not prototype-format parameter
type declarators) is an obsolescent feature.
Section 6.11.7 Function definitions
The use of function definitions with separate parameter identifier and declaration lists
(not prototype-format parameter type and identifier declarators) is an obsolescent feature.
Which the old style means K&R style
Example:
Declaration: int old_style();
Definition:
int old_style(a, b)
int a;
int b;
{
/* something to do */
}
C assumes int if no type is given on function return type and parameter list. Only for this rule following weird things are possible.
A function definition looks like this.
int func(int param) { /* body */}
If its a prototype you write
int func(int param);
In prototype you can only specify the type of parameters. Parameters' name is not mandatory. So
int func(int);
Also if you dont specify parameter type but name int is assumed as type.
int func(param);
If you go farther, following works too.
func();
Compiler assumes int func() when you write func(). But dont put func() inside a function body. That'll be a function call
As stated #Krishnabhadra, all previous responses from other users, have a correct interpretation, and I just want to make a more detailed analysis of some points.
In the Old-C as in ANSI-C the "untyped formal parameter", take the dimencion of your work register or instruction depth capability (shadow registers or instruction cumulative cycle), in an 8bit MPU, will be an int16, in a 16bit MPU and so will be an int16 an so on, in the case 64bit architectures may choose to compile options like: -m32.
Although it seems simpler implementation at high level,
For pass multiple parameters, the work of the programmer in the control dimencion data type step, becomes more demanding.
In other cases, for some microprocessors architectures, the ANSI compilers customized, leveraged some of this old features to optimize the use of the code, forcing the location of these "untyped formal parameters" to work within or outside the work register, today you get almost the same with the use of "volatile" and "register".
But it should be noted that the most modern compilers,
not make any distinction between the two types of parameters declaration.
Examples of a compilation with gcc under linux:
 
In any case the statement of the prototype locally is of no use, because there is no call without parameters reference to this prototype will be remiss.
If you use the system with "untyped formal parameter", for an external call, proceed to generate a declarative prototype data type.
Like this:
int myfunc(int param);
Regarding parameter type, there are already correct answers here but if you want to hear it from the compiler you can try adding some flags (flags are almost always a good idea anyways).
compiling your program using gcc foo.c -Wextra I get:
foo.c: In function ‘func’:
foo.c:5:5: warning: type of ‘param’ defaults to ‘int’ [-Wmissing-parameter-type]
strangely -Wextra doesn't catch this for clang (it doesn't recognize -Wmissing-parameter-type for some reason, maybe for historical ones mentioned above) but -pedantic does:
foo.c:5:10: warning: parameter 'param' was not declared,
defaulting to type 'int' [-pedantic]
int func(param)
^
1 warning generated.
And for prototype issue as said again above int func() refers to arbitrary parameters unless you exclicitly define it as int func(void) which would then give you the errors as expected:
foo.c: In function ‘func’:
foo.c:6:1: error: number of arguments doesn’t match prototype
foo.c:3:5: error: prototype declaration
foo.c: In function ‘main’:
foo.c:12:5: error: too many arguments to function ‘func’
foo.c:5:5: note: declared here
or in clang as:
foo.c:5:5: error: conflicting types for 'func'
int func(param)
^
foo.c:3:5: note: previous declaration is here
int func(void);
^
foo.c:12:20: error: too many arguments to function call, expected 0, have 1
int bla = func(10);
~~~~ ^~
foo.c:3:1: note: 'func' declared here
int func(void);
^
2 errors generated.
If the function declaration has no parameters i.e. empty then it is taking unspecified number of arguments. If you want to make it take no arguments then change it to:
int func(void);
This is why I typically advise people to compile their code with:
cc -Wmissing-variable-declarations -Wstrict-variable-declarations -Wold-style-definition
These flags enforce a couple of things:
-Wmissing-variable-declarations: It is impossible to declare a non-static function without getting a prototype first. This makes it more likely that a prototype in a header file matches with the actual definition. Alternatively, it enforces that you add the static keyword to functions that don't need to be visible publicly.
-Wstrict-variable-declarations: The prototype must properly list the arguments.
-Wold-style-definition: The function definition itself must also properly list the arguments.
These flags are also used by default in a lot of Open Source projects. For example, FreeBSD has these flags enabled when building with WARNS=6 in your Makefile.
In the old-style declarator,
the identifier list must be absent unless
the declarator is used in the head of a function definition
(Par.A.10.1). No information about the types of the parameters is
supplied by the declaration. For example, the declaration
int f(), *fpi(), (*pfi)();
declares a function f returning an integer, a function fpi returning a pointer to an integer, >and a pointer pfi to a function returning an integer. In none of these are the parameter types >specified; they are old-style.
In the new-style declaration
int strcpy(char *dest, const char *source), rand(void);
strcpy is a
function returning int, with two arguments, the first a character
pointer, and the second a pointer to constant characters
SOURCE:- K&R book
I hope it cleared your doubt..

Why is this legal in C?

I am writing a toy C compiler for a compiler/language course at my university.
I'm trying to flesh out the semantics for symbol resolution in C, and came up with this test case which I tried against regular compilers clang & gcc.
void foo() { }
int main() { foo(5); } // foo has extraneous arguments
Most compilers only seem to warn about extraneous arguments.
Question: What is the fundamental reasoning behind this?
For my symbol table generation/resolution phase, I was considering a function to be a symbol with a return type, and several parametrized arguments (based on the grammar) each with a respective type.
Thanks.
A function with no listed arguments in the prototype is deemed to have an indeterminate number, not zero.
If you really want zero arguments, it should be:
void foo (void);
The empty-list variant is a holdover from ancient C, even before ANSI got their hands on it, where you had things like:
add_one(val)
int val;
{
return val + 1;
}
(with int being the default return type and parameter types specified outside the declarator).
If you're doing a toy compiler and you're not worried about compliance with every tiny little piece of C99, I'd just toss that option out and require a parameter list of some sort.
It'll make your life substantially easier, and I question the need for people to use that "feature" anyway.
It's for backward compatibility with ancient C compilers. Back before the earth cooled, all C function declarations looked roughly like:
int foo();
long bar();
and so on. This told the compiler that the name referred to a function, but did not specify anything about the number or types of parameters. Probably the single biggest change in the original (1989) C standard was adding "function prototypes", which allowed the number and type(s) of parameters to be declared, so the compiler could check what you passed when you called a function. To maintain compatibility for existing code, they decided that an empty parameter list would retain its existing meaning, and if you wanted to declare a function that took no parameters, you'd have to add void in place of the parameter list: int f(void);.
Note that in C++ the same is not true -- C++ eliminates the old style function declarations, and requires that the number and type(s) of all parameters be specified1. If you declare the function without parameters, that means it doesn't take any parameters, and the compiler will complain if you try to pass any (unless you've also overloaded the function so there's another function with the same name that can take parameters).
1 Though you can still use an ellipsis for a function that takes a variable parameter list -- but when/if you do so, you can only pass POD types as parameters.
You haven't provided a prototype for the foo function, so the compiler can't enforce it.
If you wrote:
void foo(void) {}
then you would be providing a prototype of a function that takes no parameters.
gcc's -Wstrict-prototypes will catch this. For an error, use -Werror=strict-prototypes. The standard never specifies whether something should be a warning or an error.
Why is this legal in C?
First just to clarify the C Standard does not use the word legal.
In the C terminology, this program is not strictly conforming:
void foo() { }
int main() { foo(5); } // foo has extraneous arguments
When compiling this program, no diagnostic is required because of the function call foo(5): there is no constraint violation. But calling the function foo with an argument invokes undefined behavior. As any program that invokes undefined behavior, it is not strictly conforming and a compiler has the right to refuse to translate the program.
In the C Standard, a function declaration with an empty list of parameters means the function has an unspecified number of parameters. But a function definition with an empty list of parameters means the function has no parameter.
Here is the relevant paragraph in the C Standard (all emphasis mine):
(C99, 6.7.5.3p14) "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 paragraph of the C Standard that says the foo(5) call is undefined behavior is this one:
(C99, 6.5.2.2p6) "If the expression that denotes the called function has a type that does not include a prototype, the integer promotions are performed on each argument, and arguments that have type float are promoted to double. These are called the default argument
promotions. If the number of arguments does not equal the number of parameters, the
behavior is undefined."
And from (C99, 6.9.1p7), we know the definition of foo does not provide a prototype.
(C99, 6.9.1p7) "If the declarator includes a parameter type list, the list also specifies the types of all the parameters; such a declarator also serves as a function prototype for later calls to the same function in the same translation unit. If the declarator includes an identifier list,the types of the parameters shall be declared in a following declaration list."
See the Committee answer to the Defect Report #317 for an authoritative answer on the subject:
http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_317.htm

Resources