[comp.lang.c] Prototyping char parameters in ANSI C

gore@eecs.nwu.edu (Jacob Gore) (04/25/89)

Is this valid ANSI C (or dpANS or whatever you want to call it):

	void f(char);

	void f(c)
	   char c;
	{
	}

The version of GNU cc I have complains:

	t.c: In function f:
	t.c:5: argument `c' doesn't match function prototype
	t.c:5: a formal parameter type that promotes to `int'
	t.c:5: can match only `int' in the prototype

Is this rule for real, or is this just a gcc bug?

Jacob Gore				Gore@EECS.NWU.Edu
Northwestern Univ., EECS Dept.		{oddjob,chinet,att}!nucsrl!gore

schmidt@zola.ics.uci.edu (Doug Schmidt) (04/27/89)

In article <3950014@eecs.nwu.edu> gore@eecs.nwu.edu (Jacob Gore) writes:
++ Is this valid ANSI C (or dpANS or whatever you want to call it):
++ 
++ 	void f(char);
++ 
++ 	void f(c)
++ 	   char c;
++ 	{
++ 	}
++ 
++ The version of GNU cc I have complains:
++ 
++ 	t.c: In function f:
++ 	t.c:5: argument `c' doesn't match function prototype
++ 	t.c:5: a formal parameter type that promotes to `int'
++ 	t.c:5: can match only `int' in the prototype
++ 
++ Is this rule for real, or is this just a gcc bug?

This is a real rule.  Read the GNU C documentation:

----------------------------------------
Users often think it is a bug when GNU CC reports an error for code
like this:
 
int foo (short);
  
int foo (x)
       short x;
{
}        

The error message is correct: this code really is erroneous, because
the old-style non-prototype definition passes subword integers in
their promoted types.  In other words, the argument is really an
int, not a short.  The correct prototype is this:
 
int foo (int);
----------------------------------------  

Doug
--
On a clear day, under blue skies, there is no need to seek.
And asking about Buddha                +------------------------+
Is like proclaiming innocence,         | schmidt@ics.uci.edu    |
With loot in your pocket.              | office: (714) 856-4043 |

gwyn@smoke.BRL.MIL (Doug Gwyn) (04/27/89)

In article <3950014@eecs.nwu.edu> gore@eecs.nwu.edu (Jacob Gore) writes:
>	void f(char);
>	void f(c)
>	   char c;
>	{
>	}
>The version of GNU cc I have complains:

Once again GCC is correct.  The "old style" function definition is of
a function that is passed an int (NOT a char) argument when it is called
and which subsequently accesses the least-significant char of the int
that was passed.  The prototype declaration is for a function that is
(potentially) passed just a char, not an int.  Therefore the argument-
passing details are potentially different between the two cases, and it
is considered a function declaration/definition mismatch.

ark@alice.UUCP (Andrew Koenig) (04/27/89)

In article <3950014@eecs.nwu.edu>, gore@eecs.nwu.edu (Jacob Gore) writes:
> Is this valid ANSI C (or dpANS or whatever you want to call it):
> 
> 	void f(char);
> 
> 	void f(c)
> 	   char c;
> 	{
> 	}

No.

When you say

	void f(c)
		char c;
	{ /* stuff */ }

that is essentially equivalent to:

	void f(int c_temp)
	{
		char c = c_temp;
		{ /* stuff */ }
	}

Neither is equivalent to

	void f(char c)
	{ /* stuff */ }

See page 60 of `C Traps and Pitfalls.'
-- 
				--Andrew Koenig
				  ark@europa.att.com

kremer@cs.odu.edu (Lloyd Kremer) (04/27/89)

In article <3950014@eecs.nwu.edu> gore@eecs.nwu.edu (Jacob Gore) writes:

>Is this valid ANSI C (or dpANS or whatever you want to call it):
>
>	void f(char);
>
>	void f(c)
>	   char c;
>	{
>	}
>
>The version of GNU cc I have complains:
>
>	t.c: In function f:
>	t.c:5: argument `c' doesn't match function prototype
>	t.c:5: a formal parameter type that promotes to `int'
>	t.c:5: can match only `int' in the prototype


The responses I have seen all make reference to "old style" automatic widening
of the function argument to an int.  The fact that the original poster
specified ANSI C suggests that he knows about the "old style" rules.

In any case I know I do.  :-)  But I thought that in the new ANSI C (not old--
NEW!) you could effectively circumvent this behavior and request that small
types be received by the called function as a true char (or float, or
whatever), size and all.  There may still be temporary internal promotion due
to hardware characteristics such as the inability to push a single byte onto
the stack, but this should be transparent to the programmer.

So, I shall now ask: How do you tell the compiler that you want this *NEW*
behavior?  If a full prototype isn't good enough, what is?

-- 
					Lloyd Kremer
					Brooks Financial Systems
					...!uunet!xanth!brooks!lloyd
					Have terminal...will hack!

gwyn@smoke.BRL.MIL (Doug Gwyn) (04/28/89)

In article <8661@xanth.cs.odu.edu> kremer@cs.odu.edu (Lloyd Kremer) writes:
>So, I shall now ask: How do you tell the compiler that you want this *NEW*
>behavior?  If a full prototype isn't good enough, what is?

You have to use the prototype form in the function definition as well.

karl@haddock.ima.isc.com (Karl Heuer) (04/28/89)

In article <8661@xanth.cs.odu.edu> kremer@cs.odu.edu (Lloyd Kremer) writes:
>In article <3950014@eecs.nwu.edu> gore@eecs.nwu.edu (Jacob Gore) writes:
>>[gcc complains about]
>>	void f(char);
>>	void f(c) char c; {...}

>The responses I have seen all make reference to "old style" automatic widening
>... How do you tell the compiler that you want this *NEW* behavior?  If a
>full prototype isn't good enough, what is?

Specify a prototype on the *definition* as well as the declaration.  Thus:
	extern void f(char);
	void f(char c) {...}

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

scs@adam.pika.mit.edu (Steve Summit) (04/29/89)

In article <3950014@eecs.nwu.edu> gore@eecs.nwu.edu (Jacob Gore) writes:
>Is this valid ANSI C (or dpANS or whatever you want to call it):
>	void f(char);
>	void f(c)
>	char c;
>	{}
>
>The version of GNU cc I have complains:
>	t.c:5: argument `c' doesn't match function prototype
>	t.c:5: a formal parameter type that promotes to `int'
>	t.c:5: can match only `int' in the prototype
>Is this rule for real, or is this just a gcc bug?

Poor GNU!  They get asked this ALL THE TIME, they put in a three
line warning/explanation message, and people still don't get the
idea.

To recap, either use

	void f(int);		void f(char);
			or
	void f(c)		void f(char c)
	char c;			{}
	{}

The only difference is that the second form may allow the
argument not to be widened when passed, for those architectures
which support passing sub-word sized arguments.  (In either case,
c will act like a char within function f, being narrowed if
necessary, and having its effective address adjusted so that
something like

	f(c)
	char c;
	{
	write(1, &c, 1);
	}

works correctly on big-endian architectures.  Don't write that,
though; write(,,1) brings a machine to its knees.)

                                            Steve Summit
                                            scs@adam.pika.mit.edu

guy@auspex.auspex.com (Guy Harris) (05/02/89)

>In any case I know I do.  :-)  But I thought that in the new ANSI C (not old--
>NEW!) you could effectively circumvent this behavior and request that small
>types be received by the called function as a true char (or float, or
>whatever), size and all.

You can.

>So, I shall now ask: How do you tell the compiler that you want this *NEW*
>behavior?  If a full prototype isn't good enough, what is?

A full prototype *is* good enough.  The problem is that the code given
in the example doesn't have a full prototype *definition* of the
function; you have to define it as:

	void f(char c)
	{
		...
	}