Friday 1 April 2016

c - Declaring parameters outside the declarator



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?


Answer



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 ints, 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.


No comments:

Post a Comment

c++ - Does curly brackets matter for empty constructor?

Those brackets declare an empty, inline constructor. In that case, with them, the constructor does exist, it merely does nothing more than t...