Bug in new K&R?

D. Hugh Redelmeier hugh at dgp.toronto.edu
Thu May 12 16:21:58 AEST 1988


In article <7861 at alice.UUCP> dmr at alice.UUCP writes:
>In spite of the fact that the type void* is now guaranteed to have
>the same representation as char*, I don't think that the type
>rules of the dpANS guarantee this will work.
>
>In our defense, given that the representation of char* is the same
>as that of void*, it is reasonable to expect that you would be safe
>in reproducing the book example provided your compiler accepted it.
>However, at least as I read the last-issued version of the standard,
>the compiler might well reject it.
>
>A lot of people are going to be surprised when ANSI compilers become
>common.  As I have argued before, type qualifiers are not an unmixed
>blessing.

Here is an extract from my public comment to X3J11.  References to
the draft (X3J11/88-001) look like page/line chapter.section.subsection

I don't think that any action resulted from this.

24/5 3.1.2.5 overlapping values of signed and unsigned have same rep
25/5 3.1.2.5 void * has same rep as char *
39/18 3.3 accessing an object with type different from declaration
131/25 4.9.6.1 fprintf

There seems to be some partial compatibility presumed between
unsigned, signed, and plain types of the same width.  There
also seems to be some unspecified compatibility between char *
and void *: why else decree that their representations match?

In fprintf and its variants, d, i, o, u, x, and X conversion
specifiers work only with signed int arguments (or signed long int,
if preceded by l) (see 132/44 4.9.6.1).  But many existing programs
pass unsigned int (or unsigned long) arguments.  Surely these must
not be deemed wrong.  And I suspect that the effort of casting all
unsigned arguments will seem so silly that it won't even be done for
new programs (prototypes don't change this: they are matched by
elipsis).  Especially for the u conversion -- it would seem
downright wrong on a one's complement machine (unsigned max would
probably have to print as zero).

okOld programs, written under the "unsignedness sticks" rules
might well pass an unsigned short argument to an unsigned int
parameter.  Under the current default argument promotions, the
argument will be promoted to signed int if sizeof(int) is
greater than sizeof(short).  Thus, the program will silently
fail (i.e. violate a rule in the standard).  Of course, on most
implementations, these programs will continue to work IN SPITE OF
the standard.  The similar thing can happen to unsigned char
arguments.

Issue 1: extended parameter/argument compatibility

A new kind of type compatibility is required, say "congruence".
Two types are congruent if they are compatible.  In addition, two
integer types are congruent if their sizes are the same.
Furthermore, two pointer types are congruent if one is compatible
with pointer to char and the other is compatible with pointer to
void.

The agreement of parameters with arguments must be changed.
Argument and parameter types, if either was produced by the
default argument promotions, must at least be congruent.  If
they are congruent, but not compatible, the parameter passing
will work when the value is representable in both types, and both
representations are identical (note: in one's complement, -0 has
a distinct representation from +0).  Even though passing
parameters to congruent types will sometimes work, it should be
considered an error so that it may be diagnosed.  This is
wishy-washy, but existing programs have not carefully
distinguished signed versus unsigned, and certainly have not
passed void * parameters to library functions that now require
them.

It is to be admitted that the distinction between "working" and
"correct" is questionable.  Making this code work is important
to the mandate of X3J11: existing code is important.  I infer that
this is what some of the referenced passages of the draft standard
are trying to get at, but fail to accomplish.

Issue 2: fprintf parameter should be unsigned for o, u, x, and X

Draft 132/44: "The int argument is converted to signed decimal (d
or i), unsigned octal (o), unsigned decimal (u), or unsigned
hexadecimal notation (x or X); ..."

Since o, u, x, and X conversion specifiers do not generate
signs, it would seem most natural that they should take unsigned
numbers to format.  In fact, they take a signed number.  This
should be changed.  Note that fscanf gets these conversion
specifiers right: for them it expects the argument to be a
pointer to unsigned int.

Proposed replacement: "The int (d or i) or unsigned int (o, u, x, or X)
argument is converted to signed decimal (d or i), unsigned octal
(o), unsigned decimal (u), or unsigned hexadecimal notation (x
or X); ..."

This still leaves a problem: old programs have often printed
signed ints with these conversion specifiers.  Unless the first
issue is addressed, some programs are bound to be broken.

Hugh Redelmeier
{utcsri, utzoo, yunexus, hcr}!redvax!hugh
In desperation: hugh at csri.toronto.edu
+1 416 482 8253




More information about the Comp.lang.c mailing list