Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C Function with parameter without type indicator still works?

Tags:

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?

like image 852
Zaiping Bie Avatar asked Aug 13 '13 06:08

Zaiping Bie


People also ask

Can you have a function with no parameters?

The lesson brief states that “Functions can have zero, one or more parameters”.

Is it possible for a function to have parameters with default arguments and some without?

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.

Can we declare a function without return type in C?

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. )

Do functions always need parameters?

Parameters are essential to functions, because otherwise you can't give the function-machine an input.


2 Answers

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.

like image 139
Prof. Falken Avatar answered Nov 10 '22 01:11

Prof. Falken


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.

like image 28
nneonneo Avatar answered Nov 10 '22 01:11

nneonneo