home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #26 / NN_1992_26.iso / spool / comp / lang / c / 16068 < prev    next >
Encoding:
Text File  |  1992-11-07  |  6.8 KB  |  177 lines

  1. Path: sparky!uunet!europa.asd.contel.com!emory!swrinde!zaphod.mps.ohio-state.edu!saimiri.primate.wisc.edu!ames!agate!dog.ee.lbl.gov!horse.ee.lbl.gov!torek
  2. From: torek@horse.ee.lbl.gov (Chris Torek)
  3. Newsgroups: comp.lang.c
  4. Subject: qsort comparison functions (was "Help.  (Unix C)")
  5. Date: 6 Nov 1992 09:52:25 GMT
  6. Organization: Lawrence Berkeley Laboratory, Berkeley
  7. Lines: 164
  8. Message-ID: <27264@dog.ee.lbl.gov>
  9. References: <2214@sdrc.COM> <Bx8Cw8.5tB@portal.hq.videocart.com>
  10. Reply-To: torek@horse.ee.lbl.gov (Chris Torek)
  11. NNTP-Posting-Host: 128.3.112.15
  12.  
  13. First, some Network Etiquette:
  14.     - Choose descriptive subject lines.  `Help' is rarely
  15.       descriptive.
  16.     - Ask Unix-specific questions in Unix-specific groups.  (The
  17.       original question was not Unix-specific, as it turns out.)
  18.     - Read the FAQ.
  19.  
  20. Now: the fourth argument to qsort---the pointer to a comparison
  21. function---must be compatible with the type:
  22.  
  23.     int (*)(const void *, const void *)
  24.  
  25. This type can be described in pseudo-English as:
  26.  
  27.     pointer to function of (
  28.         pointer to read-only generic,
  29.         pointer to read-only generic
  30.     ) returning int
  31.  
  32. Note that the type `pointer to generic' (whether the generic's are
  33. read-only or read/write) is a separate type in C, quite distinct from
  34. types such as `pointer to struct foo'.  ANSI C requires that it have
  35. the same underlying representation as `pointer to char'---this is
  36. required for backwards compatibility---and as a result one can often
  37. get away with interchanging `char *' and `void *', but they are not
  38. in fact identical.
  39.  
  40. If the comparison function is ever actually called, not only must the
  41. type signatures of the pointers agree, but the actual function to which
  42. the pointer points must in fact have the final agreed-upon type.  If
  43. the function is not called, this is unnecessary (all function pointers
  44. `fit' in all other pointers, but every actual call site must use the
  45. same type signature as the corresponding actual callee; see the ANSI
  46. standard for details).  It is not immediately obvious whether this
  47. means that, e.g., `qsort(base, 0, width, (int (*)(const void *, const
  48. void *))abort)' is OK, although I would be somewhat surprised to find
  49. implementations that call the function if the number of elements being
  50. sorted is less than 2.
  51.  
  52. In article <2214@sdrc.COM> scjones@thor.sdrc.com (Larry Jones) notes:
  53. >>An ANSI compiler will, quite properly, object to this code ...
  54.  
  55. Actually, there are (at least) two cases to consider:
  56.  
  57.     A) Old-style declarations.  In this case the compiler lacks
  58.        the information it needs to detect errors.  For instance:
  59.  
  60.         extern int cmp();
  61.         qsort(table, n, sizeof(int), cmp);
  62.  
  63.        Is cmp() correct?  We have no idea, and neither does the
  64.        compiler (unless there is something else here we have not
  65.        seen).
  66.  
  67.     B) New-style declarations.  In this case the compiler has
  68.        the necessary information:
  69.  
  70.         extern int cmp(int *, int *);    /* oops! */
  71.         qsort(table, n, sizeof(int), cmp);
  72.  
  73. If you give the compiler full and correct information, as in example B,
  74. it must diagnose any error.  If the compiler fails to emit `at least
  75. one diagnostic' for example B, it is not ANSI conformant.
  76.  
  77. Of course, you can give the compiler full but incorrect information:
  78. If cmp() is defined in another file, you can write:
  79.  
  80.         extern int cmp(void *, void *);
  81.         qsort(table, n, sizeof(int), cmp);
  82.  
  83. even if cmp() actually takes two `int *'s.  Alternatively, you can use
  84. example A to withhold the full information.  In either case you have
  85. lied to the compiler, and, to quote Henry Spencer, `it will get its
  86. revenge.'  Maybe not today, but eventually....
  87.  
  88. >>Some implementations use the same representation for all pointer types
  89. >>and on those implementations you can misdefine the function and it will
  90. >>work, but this is not guaranteed and there are systems where it will
  91. >>fail.  
  92.  
  93. This is correct, although in fact `most implementations' is probably
  94. more accurate than `some implementations', at least if we do not get
  95. into the various memory models on IBM PCs.  The current known set of
  96. manufacturers/models on which different pointers either use different
  97. representations, or carry runtime checking information, is fairly small
  98. (Prime; Honeywell-Bull; Symbolics Lisp Machines; Data General Nova and
  99. Eclipse; IBM PCs with memory models).
  100.  
  101. (There exist interpreter-based systems (e.g., CenterLine C) that will
  102. carry type signatures with actual objects and values and will detect
  103. mismatches.)
  104.  
  105. In article <Bx8Cw8.5tB@portal.hq.videocart.com>
  106. dfuller@portal.hq.videocart.com (Dave Fuller) comes back with:
  107. >But, even on an ANSI compiler this will work. void is used to take on 
  108. >no predetermined meaning, or to actually mean return NOTHING from a 
  109. >function if used as a declaration type.
  110.  
  111. Not exactly.  `void' has two meanings in ANSI C:
  112.  
  113.     - A void value is a value from the empty set.  A value can
  114.       be cast to void type to indicate `I really do mean to ignore
  115.       this value; I am not ignoring it by mistake.'  Void values
  116.       may not be used (see parallel comp.std.c discussion as to
  117.       whether the standard defines `use').
  118.  
  119.     - A `pointer to (optionally qualified) void', or `void *', is
  120.       a `generic pointer' type that is *assignment compatible* with
  121.       all other object pointer types.  `Assignment compatible' means
  122.       that it is not an error to write:
  123.  
  124.         TY *p;    /* where `TY' is any object type */
  125.         void *q;
  126.  
  127.         p = q;    /* legal */
  128.         q = p;    /* legal */
  129.  
  130.       It does *not* mean that `void *' values are the *same* type
  131.       as other object pointers, although they may or may not share
  132.       underlying representations (and, again, in the special case
  133.       of `char *', they must in fact share representations).
  134.  
  135. >Also, the strcmp() function is used QUITE OFTEN in qsort.
  136.  
  137. Such usage is questionable.  In any case, strcmp can only be used
  138. directly when arrays of type (array N of char) are being sorted.  I
  139. find that most string sorts operate on arrays of type (pointer to char),
  140. where a mediator function must be used:
  141.  
  142.     char *tab[MAX];
  143.     ...
  144.     qsort(tab, n, sizeof(char *), collate);
  145.  
  146. In this case collate() should be defined along the lines of:
  147.  
  148.     int
  149.     collate(void *a, void *b)
  150.     {
  151.         char **x, **y;
  152.  
  153.         x = a;
  154.         y = b;
  155.         return strcmp(*x, *y);
  156.     }
  157.  
  158. >And if the code were not portable, it compiles and works on a non-ansi
  159. >compiler (and all of the ANSI ones i tried) ...
  160.  
  161. As the FAQ says:
  162.  
  163. 5.12:   Why won't the Frobozz Magic C Compiler, which claims to be ANSI
  164.     compliant, accept this code?  I know that the code is ANSI,
  165.     because gcc accepts it.
  166.  
  167. A:      Most compilers support a few non-Standard extensions, gcc more
  168.     so than most.  Are you sure that the code being rejected doesn't
  169.     rely on such an extension?  It is usually a bad idea to perform
  170.     experiments with a particular compiler to determine properties
  171.     of a language; the applicable standard may permit variations, or
  172.     the compiler may be wrong.
  173.  
  174. -- 
  175. In-Real-Life: Chris Torek, Lawrence Berkeley Lab CSE/EE (+1 510 486 5427)
  176. Berkeley, CA        Domain:    torek@ee.lbl.gov
  177.