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..
Related
Is it necessary to declare function before using it? Does the compiler give an error if we don't use a function declaration and call it directly. Please answer according to standard C.
If yes then what does it mean that argument of type are converted to int and float to double if arguments to function are not defined?
In ANSI C, you do not have to declare a function prototype; however, it is a best practice to use them. The only reason the standard allows you to not use them is for backward compatibility with very old code.
If you do not have a prototype, and you call a function, the compiler will infer a prototype from the parameters you pass to the function. If you declare the function later in the same compilation unit, you'll get a compile error if the function's signature is different from what the compiler guessed.
Worse, if the function is in another compilation unit, there's no way to get a compilation error, since without a a prototype there's no way to check. In that case, if the compiler gets it wrong, you could get undefined behavior if the function call pushes different types on the stack than the function expects.
Convention is to always declare a prototype in a header file that has the same name as the source file containing the function.
With prototypes, the compiler can verify you are calling the function correctly (using the right number and type of parameters).
Without prototypes, it's possible to have this:
// file1.c
void doit(double d)
{
....
}
int sum(int a, int b, int c)
{
return a + b + c;
}
and this:
// file2.c
// In C, this is just a declaration and not a prototype
void doit();
int sum();
int main(int argc, char *argv[])
{
char idea[] = "use prototypes!";
// without the prototype, the compiler will pass a char *
// to a function that expects a double
doit(idea);
// and here without a prototype the compiler allows you to
// call a function that is expecting three argument with just
// one argument (in the calling function, args b and c will be
// random junk)
return sum(argc);
}
In C, you need to define everything before you use it. I think the idea is that it can compile everything in one pass, since it always has all of the information it needs by the time it gets to it.
I'm not sure what you're asking with the second part. If the function isn't defined, it just won't work.
The short answer: in C89/90 it is not necessary, in C99 it is necessary.
In C89/90 the function does not have to be declared in order to be called. For undeclared function the compiler will make an assumption about function return type (assumes int) and about function parameter types (will derive them from the argument types at the point of the call).
In C99 the function has to be previously declared in order to be called. Note, that even in C99 there's no requirement to provide a prototype for the function, only a declaration is needed, i.e. a non-prototype declaration is OK. This means that the compiler no longer has to make any assumptions about the function return type (since the declaration always specifies it explicitly), but it still might have to make assumptions about the function parameters (if the declaration is not a prototype).
The C99 standard in 6.5.2.2 "Function call" describes what happens in a function call expression, including if no prototype has been seen by the compiler for the function:
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
Later, it describes what happens if the function call expression doesn't match what how the function is actually defined:
If the function is defined with a type that is not compatible with the type (of the expression) pointed to by the expression that denotes the called function, the behavior is undefined.
Clearly, to help ensure correctness, using function prototypes is the right thing to do. Enough such that C++ made requiring function prototypes one of the 'breaking' changes with c.
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..
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..
I don't get why does this code compile?
#include <stdio.h>
void foo() {
printf("Hello\n");
}
int main() {
const char *str = "bar";
foo(str);
return 0;
}
gcc doesn't even throw a warning that I am passing too many arguments to foo(). Is this expected behavior?
In C, a function declared with an empty parameter list accepts an arbitrary number of arguments when being called, which are subject to the usual arithmetic promotions. It is the responsibility of the caller to ensure that the arguments supplied are appropriate for the definition of the function.
To declare a function taking zero arguments, you need to write void foo(void);.
This is for historic reasons; originally, C functions didn't have prototypes, as C evolved from B, a typeless language. When prototypes were added, the original typeless declarations were left in the language for backwards compatibility.
To get gcc to warn about empty parameter lists, use -Wstrict-prototypes:
Warn if a function is declared or defined without specifying the argument types. (An old-style function definition is permitted without a warning if preceded by a declaration which specifies the argument types.)
For legacy reasons, declaring a function with () for a parameter list essentially means “figure out the parameters when the function is called”. To specify that a function has no parameters, use (void).
Edit: I feel like I am racking up reputation in this problem for being old. Just so you kids know what programming used to be like, here is my first program. (Not C; it shows you what we had to work with before that.)
void foo() {
printf("Hello\n");
}
foo(str);
in C, this code does not violates a constraint (it would if it was defined in its prototype-form with void foo(void) {/*...*/}) and as there is no constraint violation, the compiler is not required to issue a diagnostic.
But this program has undefined behavior according to the following C rules:
From:
(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,142) the types of the parameters shall be declared in a following declaration list."
the foo function does not provide a prototype.
From:
(C99, 6.5.2.2p6) "If the expression that denotes the called function has a type that does not include a prototype [...] If the number of arguments does not equal the number of parameters, the behavior is undefined."
the foo(str) function call is undefined behavior.
C does not mandate the implementation to issue a diagnostic for a program that invokes undefined behavior but your program is still an erroneous program.
Both the C99 Standard (6.7.5.3) and the C11 Standard (6.7.6.3) state:
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.
Since the declaration of foo is part of a definition, the declaration
specifies that foo takes 0 arguments, so the call foo(str) is at
least morally wrong. But as described below, there are different
degrees of "wrong" in C, and compilers may differ in how they deal
with certain kinds of "wrong".
To take a slightly simpler example, consider the following program:
int f() { return 9; }
int main() {
return f(1);
}
If I compile the above using Clang:
tmp$ cc tmp3.c
tmp3.c:4:13: warning: too many arguments in call to 'f'
return f(1);
~ ^
1 warning generated.
If I compile with gcc 4.8 I don't get any errors or warnings, even with -Wall. A previous answer suggested using -Wstrict-prototypes, which correctly reports that the definition of f is not in prototype form, but this is really not the point. The C Standard(s) allow a function definition in a non-prototype form such as the one above and the Standards clearly state that this definition specifies that the function takes 0 arguments.
Now there is a constraint (C11 Sec. 6.5.2.2):
If the expression that denotes the called function has a type that includes a prototype, the number of arguments shall agree with the number of parameters.
However, this constraint does not apply in this case, since the type of the function does not include a prototype. But here is a subsequent statement in the semantics section (not a "constraint"), that does apply:
If the expression that denotes the called function has a type that does not include a prototype
... If the number of arguments does not equal the number of parameters, the behavior is undefined.
Hence the function call does result in undefined behavior (i.e., the program is not "strictly conforming"). However, the Standard only requires an implementation to report a diagnostic message when an actual constraint is violated, and in this case, there is no violation of a constraint. Hence gcc is not required to report an error or warning in order to be a "conforming implementation".
So I think the answer to the question, why does gcc allow it?, is that gcc is not required to report anything, since this is not a constraint violation. Moreover gcc does not claim to report every kind of undefined behavior, even with -Wall or -Wpedantic. It is undefined behavior, which means the implementation can choose how to deal with it, and gcc has chosen to compile it without warnings (and apparently it just ignores the argument).
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