[comp.lang.c] function prototype problem

mark@drd.UUCP (Mark Lawrence) (11/12/88)

I compile the following code fragment:
--
#include <stdio.h>

char *rpeet  ( short, char );
char rpeet_temp[81];

char *rpeet ( num, ch )
    short num;
    char ch;
{
  int  i;

  memset( rpeet_temp, ch, num );
  rpeet_temp[num] = '\0';
  return( rpeet_temp );
}
--
and get the following gripe from my compiler (gcc 1.30):

rpeet.c: In function rpeet:
rpeet.c:9: argument `num' doesn't match function prototype
rpeet.c:9: argument `ch' doesn't match function prototype

Am I doing something wrong here or is the compiler just grumpy today?
(Please respond by e-mail.  I don't normally read this group).

Mark
					tulsun!drd!mark@Sun.COM
	DRD Corporation			mlawrence@jarsun1.ZONE1.COM
	 (918)743-3013			drd!mark@apctrc.UU.NET
					okstate!romed!drd!mark@rutgers.EDU

seanf@sco.COM (Sean Fagan) (11/14/88)

In article <310@drd.UUCP> mark@drd.UUCP () writes:
[about the gcc problem with:]
>char *rpeet  ( short, char );
>char *rpeet ( num, ch )
>    short num;
>    char ch;
[where gcc will complain about num beind redeclared as an int]

gcc is behaving as if you had done a new-style declaration (since you
can have the 'int' as optional, you can declare 'int main(ac, char **av)'),
but had also predeclared it with a prototype.  I personally think that gcc
is wrong in this respect, but haven't had enough time lately to fix it.

The problem is that gcc "does not have infinite lookahead."  Stallman
maintains that ANSI says to expand the arguments to match the prototype, and
you are declaring rpeet (in the second one) as having to arguments of type
int.

I, however, maintain what what ANSI says is that, if you declare a function
using old-style declaration (as you did), then you do not expand the
arguments unless a prototype is given; but if you use newstyle declarations
(char *rpeet ( short num, char ch) {), everything is as if you had also
given a prototype.

Does anybody who knows the ANSI draft agree with me (Chris?  Dough?
Dennis?).  BTW, K&Rr2 warns about mixing old-style and new-style
declarations; it seems to be a good idea 8-).
-- 
Sean Eric Fagan  | "Engineering without management is *ART*"
seanf@sco.UUCP   |     Jeff Johnson (jeffj@sco)
(408) 458-1422   | Any opinions expressed are my own, not my employers'.

Don_A_Corbitt@cup.portal.com (11/14/88)

>char *rpeet  ( short, char );
>char *rpeet ( num, ch)
> short num; char ch;
>--
>and get the following gripe from my compiler (gcc 1.30):
>
>rpeet.c: In function rpeet:
>rpeekkjt.c:9: argument `num' doesn't match function prototype
>rpeet.c:9: argument `ch' doesn't match function prototype
>
>Mark
>					tulsun!drd!mark@Sun.COM
>	DRD Corporation			mlawrence@jarsun1.ZONE1.COM
>	 (918)743-3013			drd!mark@apctrc.UU.NET
>					okstate!romed!drd!mark@rutgers.EDU
The problem is you are mixing declaration types.  Old style (K&R) automatically
promotes short/char to int.  New style (ANSI) lets you declare/pass shorts and
chars (although it is usually less efficient).  You should declare rpeet as
char *rpeet(short num, char ch) { ...
	Don Corbitt, CrystalGraphics, Inc.
	Don_A_Corbitt@cup.portal.com "The place with no .signature file"
	(This is my first posting, if it ends up in New Zealand and nowhere
	else, I'd appreciate mailed hints on what I shoulda done...:-)

friedl@vsi.COM (Stephen J. Friedl) (11/15/88)

In article <310@drd.UUCP>, mark@drd.UUCP (Mark Lawrence) writes:
> I compile the following code fragment:
> 
> char *rpeet  ( short, char );		/* just a declaration */
> 
> char *rpeet ( num, ch )		/* actual definition  */
> short num; char ch;
> {
>      /* foo */
>
> and get the following gripe from my compiler (gcc 1.30):
> 
> rpeet.c:9: argument `num' doesn't match function prototype
> rpeet.c:9: argument `ch' doesn't match function prototype

This is a gotcha that is not obvious -- it should be of general
interest to all using a dpANS compiler.

This compiler message is correct.  In an old-style function
declaration, the *actual* types of the arguments are those that
would result from the default argument promotions (char-->int,
short-->int, float-->double).  So the above is the same as if the
user had written:

	char *foo ( short, char );

                              vvv------------------- NOTE `int'
	char *foo ( num, ch ) int num, ch;
	{
		/* foo */


which is a mismatch.  The solution is to either declare both args
to be int everywhere or to use the prototype format for the function
definition.


The standard says [p 66, May88 dpANS]:

3.5.4.3. Function declarators (including prototypes):

     [....]
     If one [function declaration] type has a parameter-list
     type and the other type is specified by a function
     definition that contains a (possibly empty) identifier list,
     both shall agree in the number of parameters, and the type
     of each prototype parameter shall be compatible with the
     type that results from the application of the default
     argument promotions to the type of the corresponding
     identifier.

----

Followups to comp.std.c

     Steve, the stumbling lint (Hi Karl!)

-- 
Steve Friedl    V-Systems, Inc.  +1 714 545 6442    3B2-kind-of-guy
friedl@vsi.com     {backbones}!vsi.com!friedl    attmail!vsi!friedl
------------Nancy Reagan on the worm: "Just say OH NO!"------------

gwyn@smoke.BRL.MIL (Doug Gwyn ) (11/15/88)

In article <1704@scolex> seanf@sco.COM (Sean Fagan) writes:
-In article <310@drd.UUCP> mark@drd.UUCP () writes:
->char *rpeet  ( short, char );
->char *rpeet ( num, ch )
->    short num;
->    char ch;
-I, however, maintain what what ANSI says is that, if you declare a function
-using old-style declaration (as you did), then you do not expand the
-arguments unless a prototype is given; but if you use newstyle declarations
-(char *rpeet ( short num, char ch) {), everything is as if you had also
-given a prototype.

I don't have the draft Standard at hand right now, but I'm pretty sure
Stallman is right to have gcc diagnose this.  Old-style function syntax
requires widened arguments but the prototype indicates unwidened.  This
is clearly a type clash.  It is possible that the draft Standard really
says that a compiler has to straighten things out in cases like this
example, but I would find it surprising (and dangerous).

jnh@ece-csc.UUCP (Joseph Nathan Hall) (11/15/88)

In article <8889@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
 In article <1704@scolex> seanf@sco.COM (Sean Fagan) writes:
 -In article <310@drd.UUCP> mark@drd.UUCP () writes:
 ->char *rpeet  ( short, char );
 ->char *rpeet ( num, ch )
 ->    short num;
 ->    char ch;
 -I, however, maintain what what ANSI says is that, if you declare a function
 -using old-style declaration (as you did), then you do not expand the
 -arguments unless a prototype is given; but if you use newstyle declarations
 -(char *rpeet ( short num, char ch) {), everything is as if you had also
 -given a prototype.
 
 I don't have the draft Standard at hand right now, but I'm pretty sure
 Stallman is right to have gcc diagnose this.  Old-style function syntax
 requires widened arguments but the prototype indicates unwidened.  This
 is clearly a type clash.  It is possible that the draft Standard really
 says that a compiler has to straighten things out in cases like this
 example, but I would find it surprising (and dangerous).

Not only does VAX (VMS) C diagnose this, it prohibits it.
-- 
v   v sssss|| joseph hall                      || 201-1D Hampton Lee Court
 v v s   s || jnh@ece-csc.ncsu.edu (Internet)  || Cary, NC  27511
  v   sss  || the opinions expressed herein are not necessarily those of my
-----------|| employer, north carolina state university . . . . . . . . . . . 

rkl1@hound.UUCP (K.LAUX) (11/16/88)

In article <310@drd.UUCP>, mark@drd.UUCP (Mark Lawrence) writes:
| I compile the following code fragment:
| --
| #include <stdio.h>
| 
| char *rpeet  ( short, char );
| char rpeet_temp[81];
| 
| char *rpeet ( num, ch )
|     short num;
|     char ch;
| {
|   int  i;
| 
|   memset( rpeet_temp, ch, num );
			^^  ^^^		<--***NOTE***
|   rpeet_temp[num] = '\0';
|   return( rpeet_temp );
| }
| --
| and get the following gripe from my compiler (gcc 1.30):
| 
| rpeet.c: In function rpeet:
| rpeet.c:9: argument `num' doesn't match function prototype
| rpeet.c:9: argument `ch' doesn't match function prototype
| 

	I don't think the compiler is complaining at all about the function
prototype for rpeet;  it's complaining about the call to MEMSET.

	The function prototype for memset () is:

	void *memset (void *dest, int c, size_t count);
				  ^^^    ^^^^^^

	and neither 'num' nor 'ch' is of the proper type.

--rkl

rkl1@hound.UUCP (K.LAUX) (11/16/88)

	Everyone seems to have taken up the 'widened/unwidened' debate on
function rpeet.

	Would someone who has access to the gcc compiler please try to
compile the fragment with the correct argument types supplied to the
MEMSET call (see previous posting) and post the results to the net?

	'Cause I think y'all are missing the boat and that the compiler
is complaining *only* about the memset call, not the function prototype
of rpeet.

--rkl

seanf@sco.COM (Sean Fagan) (11/17/88)

In article <8889@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
}In article <1704@scolex> seanf@sco.COM (Sean Fagan) writes:
}-In article <310@drd.UUCP> mark@drd.UUCP () writes:
}->char *rpeet  ( short, char );
}->char *rpeet ( num, ch )
}->    short num;
}->    char ch;
}-I, however, maintain what what ANSI says is that, if you declare a function
}-using old-style declaration (as you did), then you do not expand the
}-arguments unless a prototype is given; but if you use newstyle declarations
}-(char *rpeet ( short num, char ch) {), everything is as if you had also
}-given a prototype.
}
}I don't have the draft Standard at hand right now, but I'm pretty sure
}Stallman is right to have gcc diagnose this.  Old-style function syntax
}requires widened arguments but the prototype indicates unwidened.  This
}is clearly a type clash.  It is possible that the draft Standard really
}says that a compiler has to straighten things out in cases like this
}example, but I would find it surprising (and dangerous).

Ooops.  Just got a nice new copy of the Draft, and you're right:  Section
3.5.4.3 (Funciton declarators (including prototypes)), page 66, lines 8-12:

	If one type has a parameter type list and the other type is
specified by a function definition that contains a (possibly empty)
identifier list, both shall agree in the number of parameters, and the type
of each prototype parameter shall be compatable with the type that results
from the application of the default argument promotions to the type of the
corresponding identifier.

Ok.  Something I may have to look in for MSC.  I still think that somebody
should fix it so that GCC will accept the mixture, unless -ansi, or
-pendantic, is specified, but that's just me (or appears to be 8-)).

So, the moral of the story:  Don't pass in char's, short's, or float's to
your subroutines unless you want a Real(tm) ANSI C compiler to choke on it
8-).

-- 
Sean Eric Fagan  | "Engineering without management is *ART*"
seanf@sco.UUCP   |     Jeff Johnson (jeffj@sco)
(408) 458-1422   | Any opinions expressed are my own, not my employers'.

mark@drd.UUCP (Mark Lawrence) (11/17/88)

In article <310@drd.UUCP>, I wrote:
	I compile the following code fragment:
	[frag deleted]

rkl1@hound.UUCP (K.LAUX) wrote:

	I don't think the compiler is complaining at all about the function
	prototype for rpeet;  it's complaining about the call to MEMSET.

	The function prototype for memset () is:
	
	void *memset (void *dest, int c, size_t count);

What the compiler _should_ gripe about and what it _does_ can, I
suppose, be argued (not by me, however, I'm out of my league).
However, when I declared the argument types in the definition using
new-style, the compiler quit complaining.

gwyn@smoke.BRL.MIL (Doug Gwyn ) (11/18/88)

In article <1736@scolex> seanf@sco.COM (Sean Fagan) writes:
>So, the moral of the story:  Don't pass in char's, short's, or float's to
>your subroutines unless you want a Real(tm) ANSI C compiler to choke on it

No, that's the wrong moral.  The correct conclusion is that prototypes
for old-style-defined functions must declare the parameters with the
correctly widened types.  In other words, when converting to prototypes
either convert EVERY reference to a function AND its definition to use
compatible prototypes (in which case any appropriate argument type can be
declared), or else use only widened parameter types.  For example,
	extern double sin(float);
is wrong because for reasons of compatibility the parameter must be
of type double by the time it reaches the innards of the function.

mac3n@babbage.acc.virginia.edu (Alex Colvin) (11/19/88)

In article <8916@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn ) writes:
> In article <1736@scolex> seanf@sco.COM (Sean Fagan) writes:
> >So, the moral of the story:  Don't pass in char's, short's, or float's to
> >your subroutines unless you want a Real(tm) ANSI C compiler to choke on it
> 
> No, that's the wrong moral.  The correct conclusion is that prototypes
> for old-style-defined functions must declare the parameters with the
> correctly widened types.

It's true.  Be careful declaring a (float) parameter in K&R C.  What
happens when you pass its address to something that expects (float *)?

Most stuff works OK when you're on a little-end address machine where the
beginning of (int) looks like (char).  Less common is where the beginning of
(double) looks like a (float).  Kids, don't try this on your big-end or
word addressed machines at home.  You'll get the wrong (char).

I understand that ANSI C may be an annoyance to those of you with VAXes, but I
can't afford one and it sure helps me.

seanf@sco.COM (Sean Fagan) (11/20/88)

In article <412@babbage.acc.virginia.edu> mac3n@babbage.acc.virginia.edu (Alex Colvin) writes:
>In article <8916@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn ) writes:
>> In article <1736@scolex> seanf@sco.COM (Sean Fagan) writes:
>> >So, the moral of the story:  Don't pass in char's, short's, or float's to
>> >your subroutines unless you want a Real(tm) ANSI C compiler to choke on it
[both Doug and Alex complain]

*arggh*!  I forgot the blasted '8-)'!  I *like* ANSI C!  I also *like*
passing in char, short, or floats, when it will make my meaning clearer!

However, I also prefer declaring parameters the old-style way, since it can
save me typing.  I want the best of both worlds!  Surely this isn't too much
to ask for? 8-;

Again, I think most ANSI-C compilers will support this as an option, and I
*still* think GNU C should (just wait until I can get some free time...!).

-- 
Sean Eric Fagan  | "Engineering without management is *ART*"
seanf@sco.UUCP   |     Jeff Johnson (jeffj@sco)
(408) 458-1422   | Any opinions expressed are my own, not my employers'.

gwyn@smoke.BRL.MIL (Doug Gwyn ) (11/22/88)

In article <1763@scolex> seanf@sco.COM (Sean Fagan) writes:
>However, I also prefer declaring parameters the old-style way, ...
>Again, I think most ANSI-C compilers will support this as an option, ...

It's not an option; ANSI C requires that old-style declarations and
definitions also be supported.  It is the attempt to mix both styles
for the same function that causes potential problems.