www.delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1996/04/11/00:03:36

From: j DOT aldrich6 AT genie DOT com
Message-Id: <199604110342.AA171244156@relay1.geis.com>
Date: Thu, 11 Apr 96 03:44:00 UTC 0000
To: djgpp AT delorie DOT com
Mime-Version: 1.0
Subject: Re: A Proper Cast for a Funtio

Reply to message 3038710    from JETMAN AT GNN DOT CO on 04/10/96  5:10PM


>	John:  It's dealing w/ routines exactly like qsort() where
>I need fn casts.  qsort() wants something like this passed as the
>last param:  (int (*) (const void *, const void *)).  Let's say
>I have a comparison fn that looks almost like that, exc that its
>params don't have the const attr.  Ok, I use a cast to tell the
>compiler: go ahead and use my routine, bec *I* know it's okay.  No (real)
>conversion is done and things work exactly the way I want.  Or perhaps
>my comparison routine returns a long or char value.  No prob, the
>cast is safe and there *is* an implicit conversion (ie. truncation
>or sign extension), but *I* know it's safe for the compiler to do.

What I would do in that case is make my routine conform exactly to the
format that qsort() wants, and make my typecasts *within* the function.
Either that or a 'shell' function that calls the real function with the
correctly
typecasted arguments.  For example, to get strcmp() to work with qsort(),
one simply does something like this:

int sort_fun( const void *a, const void *b )
{
    return strcmp( (char *)a, (char *) b );
}

Is there any reason why you can't do something similar with your function,
either having a 'shell' function convert each of the arguments and return
values to the proper type, or having your function do this itself?  All qsort()
wants is a negative or zero number if the elements don't get swapped, and
a positive number if they do.  Much easier than trying to do a typecast on
the function itself.

>If my comparison routine returned an unsigned, that would be an
>example of an unsafe cast, in this example, since the results of
>certain comparisons could never be passed back to qsort().  If my
>comparison fn spec'd formal args of float *, instead of void *,
>again usg a cast would be no prob.  Other explicit type coercions and
>implicit conversions must be evaluated on a case-by-case basis, since
>beyond the rules governing sign-extension and truncation of fractions
>(ie. bet integral and/or floating pt types), one is always on unstable
>ground, even if one can force the compiler to comply w/ one's wishes.

I have looked in some detail at the code for qsort().  It doesn't care in the
least what your array actually contains as long as you tell it how many
bytes each element has.  When it calls the comparison function, it simply
passes a pointer to the first byte of the elements to be compared.  When it
performs a swap, it copies the elements byte-for-byte, without even the
slightest implicit or explicit reference to their contents or significance.  It
_passes_ the pointers as const void *, but you can typecast them to
whatever you want them to be, as long as it is compatible with the contents
of the array to be sorted.  You can even discard the 'const' as long as you
use an explicit typecast.  I have done so myself for any number of functions
that accepted const pointers as arguments, but needed to return non-const
values derived from those arguments.

For example, I have a program where I needed to sort a large number of
structures, each of which contained a string and an integer.  The array
was malloc()'ed at runtime, and after being loaded with the appropriate
data, I just called qsort() like so:

--- begin program fragment ---

    /* now we have all keywords in the list.  Sort 'em. */
    qsort( help_sort_list, help_sort_list_size, sizeof( *help_sort_list ),
        sort_list_compare );

    return;
}



int sort_list_compare( const void *v1, const void *v2 )
{
    struct help_sort_list_type *p1 = ( struct help_sort_list_type * ) v1;
    struct help_sort_list_type *p2 = ( struct help_sort_list_type * ) v2;

    return strcmp( p1->name, p2->name );
}

--- end program fragment ---

If I had used a comparison function with a different significance to the
return value, the shell function could have handled that as well, without
bothering qsort() in the slightest.

>	This is precisely what I've been refering to.  IMHO, that's
>what casting (type coercion) is *all* about, at least in C.  One
>really can't go wrong, as long as one stays w/in the constraints
>detailed above.

Yep!  I have discovered so many wonderful things about types and
type conversions since I started working with C.  Anything is possible,
as long as you are careful!  :)

>	BTW:  I've been meaning to get a copy of the official ANSI C
>std for a while (Standard C by Brodie and Plauger has always served me
>well, but having the definitive ref is preferable), but I never seem to
>remember to order it from ANSI.  Does anyone know of a FTP site where
>I could simply d/l it as a Postscript or ASCII text file, if such an
>animal exists ?

That would be nice.  I'd like to see that too.  Of course, individual compilers
have added so much to ANSI C that it is only generally useful as a guide
for what WILL work, no matter what compiler you use.  But then, that's the
idea.

John

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019