Bug in users command

John F Haugh II jfh at rpp386.cactus.org
Thu Jan 24 03:06:55 AEST 1991


In article <6182:Jan2222:06:3991 at kramden.acf.nyu.edu> brnstnd at kramden.acf.nyu.edu (Dan Bernstein) writes:
>For comp.std.c readers: This argument started when I said that the BSD
>users.c appears to be incorrect. It passes a two-dimensional character
>array to qsort(), but the comparison function was expecting just a
>pointer to characters. John says that's correct.

Repeat after me ... the type which qsort() expects is a (void *) (or
in the older circles, (char *)).  The comparision function should also
be declared to accept two (void *)'s (or in the older circles, (char *)'s).
This is all in the documentation.

In the "Notes" section for my compiler -

	"The pointer to the base of the table should be of type
	 pointer to element, and cast to pointer to character."

This is the same vein as every other compiler in existence, and I
believe (because my ANSI is not here right now) that ANSI C declares
qsort() to have the following prototype (modulo a few "const"'s here
and there) -

void qsort (void *, unsigned, unsigned, int (*) (void *, void *));

That should make it pretty clear what type qsort() expects.

>There is no array being passed. A *pointer* to the array is being
>passed.

According to the standard, a pointer to a character or a pointer to
a void is being passed.  There is no mechanism in the standard to
create a pointer to an arbitrary object, or to find out the type of
an object which has been passed to you.

You are more than free to do

int scmp (char (*a)[UT_NAMESIZE], char (*b)[UT_NAMESIZE])
{ ... }

but that most certainly is incorrect, according to the standard,
since that function is not (int (*) (void *, void *)).  The best
you could do is

int scmp (void *_a, void *_b)
{
	char (*a)[UT_NAMESIZE] = _a;
	char (*b)[UT_NAMESIZE] = _b;

	...
}

if that gives you some sense of moral superiority, but you are
stuck doing

	strncmp ((char *) a, (char *) b, sizeof *a);

by your logic in that case.

How would qsort() create the parameters?  You can't do

	(*compar) ((typeof base) (base + n)), ...)

there simply is no mechanism to cast a pointer dynamically to some
other type.  How is qsort ever going to create the ((*c)[UT_NAMESIZE])
pointer?  There is no type information regarding what "base" was on
the other side of the function call.  qsort doesn't know, doesn't care
and can't find out.

Finally, by the rule which says that (void *) and (char *) have the
same representation, the BSD use of (char *) in place of (void *)
is perfectly acceptable.

Now are you happy?
-- 
John F. Haugh II                             UUCP: ...!cs.utexas.edu!rpp386!jfh
Ma Bell: (512) 832-8832                           Domain: jfh at rpp386.cactus.org
"13 of 17 valedictorians in Boston High Schools last spring were immigrants
 or children of immigrants"   -- US News and World Report, May 15, 1990



More information about the Comp.bugs.4bsd.ucb-fixes mailing list