[comp.lang.c] Prototypes with old style definitions

amr@dukee.egr.duke.edu (Anthony M. Richardson) (02/07/90)

Can someone with access to the (proposed?) ANSI standard answer the
following for me?

Does the Standard specify what action should occur when old style
function definitions are preceded by new style declarations?
That is, if we have

=======================
float foo(float, int);

float foo(x, n)
float x;
int n;
{ ......... }
=======================
what does the standard say about parameter conversions in this case?

I see only three possible answers:
(1) foo must assume that x will be passed as a float and must return a float,
    i.e. must obey the prototype,
(2) the standard does not allow mixing of new style declarations and old 
    style definitions,
(3) behavior is implementation dependent.

I guess there could be a (4):
(4) foo must do old style parameter conversions (specifically float -> double),
but this doesn't seem too likely.

Email would be appreciated as I don't subscribe to this group.

Thanks,
Tony Richardson       amr@dukee.egr.duke.edu

bright@Data-IO.COM (Walter Bright) (02/13/90)

In article <626@cameron.cs.duke.edu> amr@dukee.egr.duke.edu (Anthony M. Richardson) writes:
<	float foo(float, int);
<
<	float foo(x, n)
<	float x;
<	int n;
<	{ ......... }
<what does the standard say about parameter conversions in this case?

"Syntax error!" But seriously, the second definition is equivalent to:

	float foo(tmp,n)
	double tmp;
	int n;
	{	float x = tmp;
		....
	}

Thus the syntax error. This and similar examples bite lots of code that
is being converted to ANSI prototypes.

mark@Jhereg.Minnetech.MN.ORG (Mark H. Colburn) (02/13/90)

In article <2329@dataio.Data-IO.COM> bright@Data-IO.COM (Walter Bright) writes:
>In article <626@cameron.cs.duke.edu> amr@dukee.egr.duke.edu (Anthony M. Richardson) writes:
<<	float foo(float, int);
<<
<<	float foo(x, n)
<<	float x;
<<	int n;
<<	{ ......... }
<"Syntax error!" But seriously, the second definition is equivalent to:
<
<	float foo(tmp,n)
<	double tmp;
<	int n;
<	{	float x = tmp;
<		....
<	}


I was under the impression that the standard allowed parameters to be
passed between functions without type coersion in this manner as long
as there was a function prototype in effect.  If no function prototype
is in effect then the second example would be correct.  However, using
prototypes, the former should be correct.  If you wanted doubles
passed, you could always do:

	double foo(double, int);

	double
	foo(double x, int n)
	{ ... };



-- 
Mark H. Colburn                       mark@Minnetech.MN.ORG
Open Systems Architects, Inc.

raeburn@athena.mit.edu (Ken Raeburn) (02/14/90)

In article <1990Feb13.133503.19793@Jhereg.Minnetech.MN.ORG> mark@Jhereg.Minnetech.MN.ORG (Mark H. Colburn) writes:
>In article <2329@dataio.Data-IO.COM> bright@Data-IO.COM (Walter Bright) writes:
(basically that
	float foo (float, int);
	float foo (x, n) float x; int n; { /* ... */ }
are incompatible, because the latter implies
	float foo (double arg_to_treat_as_float, int n))

>I was under the impression that the standard allowed parameters to be
>passed between functions without type coersion in this manner as long
>as there was a function prototype in effect.  If no function prototype
>is in effect then the second example would be correct.  However, using
>prototypes, the former should be correct.  If you wanted doubles

I had this argument a while back with a friend of mine from Lotus.  As I
recall, she was claiming that all of the ANSI C compilers she'd worked with
except gcc did what you suggest.  (I don't know which compilers or even which
machines she was working with -- mostly in the PC world, I think -- but I hope
not to have to use them.)

But there is a section of the ANS (which I can't point you to, since I don't
have my draft copy here) which says that the declaration implied by the
old-style definition is compatible only with prototypes with (among other
things) argument types that are compatible with the *promoted* type of the
corresponding argument in the definition.

The arguments I see basically go two ways:

1) Let's make the prototype not modify the behavior of the function.  This
   way, the compiled function doesn't depend on whether the prototype was
   visible (and therefore providing more information) when the definition was
   compiled.  (This is the course X3J11 chose.)

2) Let's make the prototype modify the function's behavior.  This means that
   the definition does not contain all the information about the function that
   is needed to compile it.  (Of course, to make life easier, we'll only
   require the prototype be in scope for the definition when you want to omit
   the default promotions.)  This way, we can get exactly what we want with
   our new fancy ANSI-compliant compilers, and our old crufty compilers can
   still swallow the code (since we're using "#if __STDC__", of course!), even
   though they'll waste extra space in the argument list and so forth.

I can make no claim as to what X3J11's reasoning was, but from at least one
point of view, option 1 above seems sufficiently persuasive.  (Of course,
my friend held the opposite point of view, but....)

-- Ken

walter@hpclwjm.HP.COM (Walter Murray) (02/15/90)

Mark H. Colburn writes:

Concerning the example:

><<	float foo(float, int);
><<
><<	float foo(x, n)
><<	float x;
><<	int n;
><<	{ ......... }

> I was under the impression that the standard allowed parameters to be
> passed between functions without type coersion in this manner as long
> as there was a function prototype in effect.  

That is true, but if you have a parameter of type float and you want
to prevent promotion to double, both the declaration (if given) and
the definition must use prototypes.  This is a case where you can't
mix a prototype declaration and an old-style definition.

Walter
----------