The C standard states that, for a function definition, if the declarator includes an identifier list, the types of the parameters shall be declared in a following declaration list. Apparently this makes a difference.
extern int max(int a, int b)
{
return a > b ? a : b;
}
extern int max(a, b)
int a, b;
{
return a > b ? a : b;
}
Here int a, b; is the declaration list for the parameters. The difference between these two definitions is that the first form acts as a prototype declaration that forces conversion of the arguments of subsequent calls to the function, whereas the second form does not.
What does this mean for the programmer and does it affect the code the compiler produces?
In a function declaration, or prototype, the type of each parameter must be specified. In the function definition, the type of each parameter must also be specified. In the function definition, if the type of a parameter is not specified, it is assumed to be int .
A formal parameter declaration specifies the name and data type of the parameter, and (optionally) its mode and default value. A formal parameter declaration can appear in the following: "Function Declaration and Definition" "Procedure Declaration and Definition" "CREATE FUNCTION Statement"
Parameter, local, and instance variablesParameters are declared in between the parentheses in the header of a method. Local variables are declared between the curly-braces of a method, in a statement (which needs to end with a semicolon).
The lesson brief states that “Functions can have zero, one or more parameters”.
It means that in the second case, it's the responsibility of the caller to ensure that the arguments provided are of the correct type; no implicit conversion will be provided (other than the default argument promotions). From section 6.5.2.2:
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.
...
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.
So calling code like this will be ok:
char x = 3;
char y = 7;
max(x, y); // Equivalent to max((int)x, (int)y)
because x
and y
are promoted to int
before being placed on the stack.
However, code like this will not be ok:
double x = 3.0;
long y = 7;
max(x, y); // Uh-oh
x
and y
will be placed on the stack as double
and long
, but max()
will attempt to read two int
s, which will result in undefined behaviour (in practice, the raw bits will be reinterpreted).
This is one reason not to use the second form; the only reason it's in the standard is to provide backward compatibility with (extremely) legacy code. If you're using GCC, you can enforce this by using the -Wold-style-definition
flag; I would hope that other compilers would offer something equivalent.
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