Mixing Old Declarations with Prototypes Causes Passing Errors

ID Number: Q38729

5.10

MS-DOS

Question:

It is my understanding that both of the following functions should

produce identical results:

float AAA(float x1, float x2)

{

x1 = x2;

}

float BBB(x1,x2)

float x1,x2;

{

x1 = x2;

}

However, they don't. Looking at the code, I see that in BBB, the two

parameters are treated as double instead of float. When I compile with

the /Zg switch, which generates function prototypes, the following

prototypes are generated:

extern float AAA(float x1, float x2);

extern float BBB(double x1, double x2);

Why is this behavior occuring?

Response:

The following is from the May 5, 1988 ANSI draft, Section 3.3.2.2:

"If the expression that denotes the called function has a type that

does not include a prototype...arguments that have type float are

promoted to double.

"If the expression that denotes the called function has a type that

includes a prototype, the arguments are implicitly converted, as if

by assignment, to the types of the corresponding parameters."

For AAA, you're using the new function definition style. Note that if

you call this function (perhaps in another module) without a prototype

in scope, you'll have problems because you'll pass doubles rather than

floats (see first paragraph above).

BBB uses the old style of definition as described in K & R. Because

K & R specified that the floats are to be widened to doubles when

they're passed to functions (and in a variety of other situations

as well), the old style declarations maintain the old semantics.

Therefore, the /Zg switch is correctly generating the function

prototypes.

Your program wouldn't run when you declared the following prototype

before calling BBB because the prototype that was in scope when you

CALLED BBB did not match the implicit prototype generated when the

function was defined:

void BBB(float, float);

As a result, you passed floats to a function that was expecting

doubles.