[comp.lang.c] `char' parameters

rns@se-sd.sandiego.ncr.com (Rick Schubert) (08/31/88)

I believe I have found a bug in a C compiler I am using, but I cannot
find anything in K&R I or the Draft ANSI Standard that <<directly>>
addresses the issue.  The compiler in question is pre-draft-ANSI, but
I frequently look at the Draft in such situations where only K&R I
features are involved.

Anyway, the situation involves parameters of type `char'.  Remember that
this is pre-draft-ANSI, so that function prototypes do not exist.
If I define a function `f' as follows:

	f(c)
	char	c;
	{
		...
	}

the compiler in question gives a warning that type type of `c' is
being changed to `int'.

I could not find anything in K&R I or the Draft that addresses such
parameters.  The closest I could find is in K&R I section 2.7 (page 42):

	Since a function argument is an expression, type conversions
	also take place when arguments are passed to functions: in
	particular, `char' and `short' become `int', and `float'
	becomes `double'.  This is why we have declared function
	arguments to be `int' and `double' even when the function is
	called with `char' and `float'.

I was aware of what happens to the <<argument>>.
The passage does not explain, however, what happens when one declares the
parameter to be type `char' or `float'; I don't see this prohibited
anywhere.

To continue: when I first saw the warning from the compiler, I thought
that the warning was invalid, since I thought that it was okay to declare
such a parameter.  I knew about the treatment of function <<arguments>>,
but I felt that, as long as the compiler generated code to reference the
correct byte of the `int', that things would work out (this is what other
compilers I have used have done).  I even thought that it would be safe
to ignore the warning, since, in most contexts, treating the parameter
as an `int' or a `char' would not make any difference: in an expression,
the `char' would be promoted to an `int'; on assignment, an `int' would
be properly truncated to a `char'.  The problem comes in taking the
address of the parameter.  Ignoring the problem that `&c' would produce
an `int *' rather than a `char *', which byte does `&c' point to?  The
programmer who wrote `char c' would expect it to point to the byte
containing the character that was passed to the function; i.e., in the
following example:

	   .
	   .
	   .
	f('A');
	   .
	   .
	   .

f(c)
char	c;
{
	g(&c);
}

g(p)
char	*p;
{
	char	c2;

	c2 = *p;
}

the programmer would expect `p' to point to a byte containing 'A', so
that `c2' would be assigned 'A'.  With the compiler in question, however,
`p' points to the high-order byte of a word whose low-order byte is 'A',
i.e. the word contains the value 0x00000041, and `p' points to 0x00 rather
than 0x41, so that `c2' gets assigned 0x00 or '\0'.

My questions are:

	1. Is it illegal to declare a parameter to be of type `char'?
	2. If not, is it valid to treat the parameter as type `int'?
	3. If so, what does the unary `&' operator do to such a variable?
	4. Where is this addressed in K&R I?
	5. Where is this addressed in the Draft (assuming no prototypes)?

Thanks for any useful information.

-- Rick Schubert (rns@se-sd.sandiego.NCR.COM)

gwyn@smoke.ARPA (Doug Gwyn ) (09/01/88)

In article <1616@se-sd.sandiego.ncr.com> rns@se-sd.sandiego.NCR.COM (Rick Schubert) writes:
>	1. Is it illegal to declare a parameter to be of type `char'?

No, but it's rather pointless since the parameter really IS passed
as an int.  The compiler HAS to make the adjustment.

>	2. If not, is it valid to treat the parameter as type `int'?

This is recommended practice.

>	3. If so, what does the unary `&' operator do to such a variable?

Takes its address, just as for any other int.

swilson%thetone@Sun.COM (Scott Wilson) (09/01/88)

>I was aware of what happens to the <<argument>>.
>The passage does not explain, however, what happens when one declares the
>parameter to be type `char' or `float'; I don't see this prohibited
>anywhere.

I was bitten by the float/double version of this once.  I had declared
a formal parameter as a float, took its address and passed what I
thought was a float pointer to another function.  Anyway, I don't have
K&R 2nd edition around, but K&R 1st edition does describe float formal
arguments.  From page 205:

	C converts all float actual parameters to double, so formal
	parameters declared float have their declaration adjusted
	to read double.

Your're right though, that int vs. char is not explicitly mentioned
in this section.


--
Scott Wilson		arpa: swilson@sun.com
Sun Microsystems	uucp: ...!sun!swilson
Mt. View, CA

bgibbons@Apple.COM (Bill Gibbons) (09/01/88)

In article <1616@se-sd.sandiego.ncr.com> rns@se-sd.sandiego.NCR.COM (Rick Schubert) writes:
>I believe I have found a bug in a C compiler I am using ...
>If I define a function `f' as follows:
>	f(c)
>	char	c;
>	{
>		...
>	}
>
>the compiler in question gives a warning that type type of `c' is
>being changed to `int'.
> ...

In section 3.7.1 of the draft standard, it says:
   On entry to the function the value of each argument expression shall be
   converted to the type of its corresponding parameter, as if by assignment
   to the parameter.

This is known as _narrowing_.  It is very important, for exactly the reason
you point out: if the parameter is not narrowed, and you take its address,
the pointer is to a different type than expected.

Narrowing is very easy for a compiler to do: for CHAR and SHORT, it just
adjusts the stack offset at which it thinks the value was passed, and changes
the type.  (On PDP11 etc, it doesnt even change the offset.)  Floating-point
is a little harder on most machines; it needs an explicit conversion.

This caused me a lot of effort last fall, when I was porting a UNIX application
to IDRIS running on an Atari box.  The Whitesmiths compiler did not do
narrowing, and I had to modify the code (with a tool) to add explicit
narrowing.  Without a tool to systematically change the code, it would have
been hopeless.  (After I got it working and it showed at Comdex, Atari
cancelled the product.  Fortunately, someone else was paying :-)

Bill Gibbons
(contractor)
bgibbons@apple.com