The code is as following:
int func(param111) { printf("%d\n", param111); return param111; } int main() { int bla0 = func(99); int bla1 = func(10,99); int bla2 = func(11111110,99,10001); printf("%d, %d, %d\n", bla0, bla1, bla2); }
Compile result:
zbie@ubuntu:~$ gcc -Wall -g -std=c99 -O2 zeroparam.c zeroparam.c: In function ‘func’: zeroparam.c:2: warning: type of ‘param111’ defaults to ‘int’
Run result:
zbie@ubuntu:~$ ./a.out 99 10 11111110 99, 10, 11111110
I know the code should be ok if the func with zero parameters, such as int func() which will accept any inputs. But how does this code get compiled and ran successfully?
The lesson brief states that “Functions can have zero, one or more parameters”.
It is possible for a function to have some parameters with default arguments and some without. A function's return data type must be the same as the function's parameter(s). One reason for using functions is to break programs into manageable units, or modules. You must furnish an argument with a function call.
In C there are no subroutines, only functions, but functions are not required to return a value. The correct way to indicate that a function does not return a value is to use the return type "void". ( This is a way of explicitly saying that the function returns nothing. )
Parameters are essential to functions, because otherwise you can't give the function-machine an input.
This behaviour is to provide backwards compatibility with older versions of the language, the K&R version of the language. When GCC encounters an "old style" function, it conforms to the old K&R C behaviour which implies no warnings in this situation.
Indeed, if you change the function to: int func(int param111)
, you do get the expected warnings:
x.c: In function ‘main’: x.c:11:5: error: too many arguments to function ‘func’ x.c:2:5: note: declared here x.c:12:5: error: too many arguments to function ‘func’ x.c:2:5: note: declared here x.c:14:1: warning: control reaches end of non-void function [-Wreturn-type]
(Tested with GCC 4.7.3 and "gcc -std=c99 -Wall x.c && ./a.out")
Or to quote JeremyP from the comments: "In K&R C it was perfectly fine to call a function with as many arguments as you like, because the ellipsis notation wasn't invented then.".
Note that a compiler can show as many extra warnings it wants and still conform to the standard. For instance Apple's compiler warns about this code.
The function declaration is being interpreted as a K&R style function declaration because it lacks types. In standardese, this is called a function declaration with an identifier list, as opposed to a parameter type list as in the usual declaration.
According to the C99 specification, 6.9.1/7, only function definitions with a parameter type list are considered to be function prototypes. The K&R style uses an identifier list instead, and so is not considered to have a prototype.
Function calls to functions without prototypes are not checked for parameter counts or types (per 6.5.2.2/8, "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"). Thus, it is legal to call a function declared in the K&R style with any number and type of arguments, but per 6.5.2.2/9 a call with invalid types will produce undefined behaviour.
As an illustration, the following will compile without any warnings (on gcc -Wall -Wextra -pedantic -std=c99 -O
):
#include <stdio.h> void *func(param111) char *param111; { printf("%s\n", param111); return param111; } int main() { void *bla0 = func(); void *bla1 = func(99); void *bla2 = func(11111110,99); printf("%p, %p, %p\n", bla0, bla1, bla2); return 0; }
despite obviously having incorrect parameter types and counts.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With