home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #26 / NN_1992_26.iso / spool / comp / lang / c / 16063 < prev    next >
Encoding:
Internet Message Format  |  1992-11-07  |  4.4 KB

  1. Path: sparky!uunet!sdrc!thor!scjones
  2. From: scjones@thor.sdrc.com (Larry Jones)
  3. Newsgroups: comp.lang.c
  4. Subject: Re: Help.  (Unix C)
  5. Summary: qsort comparison functions
  6. Message-ID: <2223@sdrc.COM>
  7. Date: 5 Nov 92 16:20:27 GMT
  8. References: <2214@sdrc.COM> <Bx8Cw8.5tB@portal.hq.videocart.com>
  9. Sender: news@sdrc.COM
  10. Lines: 71
  11.  
  12. In article <Bx8Cw8.5tB@portal.hq.videocart.com>, dfuller@portal.hq.videocart.com (Dave Fuller) writes:
  13. > scjones@thor.sdrc.com (Larry Jones) writes:
  14. > : An ANSI compiler will, quite properly, object to this code -- it is
  15. > : neither correct nor portable.  The comparison function *must* be
  16. > : defined with two "void *" arguments (or "char *" if your compiler is
  17. > : too old to support "void *"); that's what qsort calls it with.  Some
  18. > : implementations use the same representation for all pointer types and
  19. > : on those implementations you can misdefine the function and it will
  20. > : work, but this is not guaranteed and there are systems where it will
  21. > : fail.  
  22. > : 
  23. >    First of all, i don't use an ANSI compiler except for about 20%
  24. > of my code (the declaration of the function should have helped on that).
  25.  
  26. That's too bad -- using an ANSI compiler and prototypes can point out a
  27. lot of subtle errors (like this one) that aren't easily found otherwise.
  28.  
  29. > But, even on an ANSI compiler this will work. void is used to take on 
  30. > no predetermined meaning, or to actually mean return NOTHING from a 
  31. > function if used as a declaration type. malloc returns void *, but it
  32. > won't complain if you dont cast the return value and assign it to a 
  33. > char *. Also, the strcmp()  function is used QUITE OFTEN in qsort.
  34. > look at the definition for it though strcmp(const char*,const char*)
  35. > it doesn't have void * declared as you say a routine that qsort calls
  36. > *must* have.
  37.  
  38. When you assign a void * to another pointer type, there is a conversion
  39. that takes place, just like when you assign a float to an int.  Neither
  40. requires a cast, but the data is converted from one type to another. 
  41. Now, as I said, many systems use the same representation for all
  42. pointer types; on these systems you don't actually have to do anything
  43. to convert from one pointer type to another, just like you don't have
  44. to do anything to convert from a signed int to an unsigned int on a 2's
  45. complement system (but you DO have to do things on a 1's complement or
  46. sign/magnitude system).
  47.  
  48. However, what we're talking about with qsort is not assignment where the
  49. compiler knows to apply the appropriate conversion.  What we're talking
  50. about is calling a function with one type of argument but defining it
  51. with a different type of argument.  This is like calling sqrt() with an
  52. int argument (and no prototype).  The compiler doesn't know any better,
  53. so it goes ahead and passes an int, but sqrt() treats it like a double
  54. whose value is usually nothing like the value of the int, and you get
  55. back a garbage result.  The same thing happens here: qsort() calls the
  56. comparison function a passes it two void * arguments, but your
  57. comparison function treats those arguments like structure pointers.  If
  58. structure pointers happen to have the same representation as void
  59. pointers, it works; if not, you get garbage.  The only difference
  60. between this and the sqrt() case is that int and double have different
  61. representations on most machines so that almost never works, but struct
  62. pointers and void pointers have the same representation on most machines
  63. so it usually does work.
  64.  
  65. char * and void * are guaranteed to have the same representation, so you
  66. are guaranteed that you can get away with that error, but technically it
  67. is still an error: void * and char * are different types.  Of course, if
  68. you don't have an ANSI compiler, you *can't* use void *, you have to use
  69. char *, so the guarantee allows existing programs to continue to work.
  70.  
  71. > And if the code were not portable, it compiles and works on a non-ansi
  72. > compiler (and all of the ANSI ones i tried), so please take back the
  73. > part where you say the code is not correct. it is.
  74.  
  75. The exact code you posted will, in fact, compile on an ANSI compiler
  76. without diagnostics, but only because you haven't given the compiler
  77. enough information to know it's wrong.  Use prototypes and it will no
  78. longer compile.  It's wrong.
  79. ----
  80. Larry Jones, SDRC, 2000 Eastman Dr., Milford, OH  45150-2789  513-576-2070
  81. larry.jones@sdrc.com  or  ...uunet!sdrc!larry.jones
  82. These findings suggest a logical course of action. -- Calvin
  83.