0
votes

I'm writing this program which needs to do a qsort() on a table. I've done extensive research on the internet, but I'm still missing something. Below is selected portions of the source code.

#define NOSLACK __attribute__((packed))

#define TABWIDTH 100                                 /* width of big table */

#define TABSIZE 100                      /* number of entries in big table */

struct ELEMEN 
   {char flags;                           /* flags pertaining to this task */
    short int tasknum;  /* number of THIS task (excluding any step number) */
    short int numpre;                   /* number of prereqs this task has */
    short int numpost;                 /* number of postreqs this task has */
    short int prereqs[0];      /* table of prereqs (omitted if numpre = 0) */
    short int postreqs[0];   /* table of postreqs (omitted if numpost = 0) */
    char fragment[TABWIDTH                    /* fragment of the descrip-  */
     - sizeof(char)                           /* tion; as much as will fit */
     - sizeof(short int) * 3];} NOSLACK;

           /* the lengths of all the above fields should total to TABWIDTH */

    struct ELEMEN bigtable[TABSIZE];

short int e35(const void*, const void*);

short int main(int argc, char* argv[])

    qsort(g.bigtable, numelem, TABWIDTH,         /* sort table using e35() */
     e35);                                         // <--- PROBLEM HERE

short int e35(const void* elem1, const void* elem2)         /* sort tasks  */
   {return(memcmp(                                          /* into se-    */
     (short int*)&((struct ELEMEN*)elem1)-> tasknum,        /* quence by   */
     (short int*)&((struct ELEMEN*)elem2)-> tasknum,        /* task number */
     sizeof(short)
     ));

The problem is in the call to qsort(). If the last parameter is just e35, I get the warning message: warning: passing argument 4 of ‘qsort’ from incompatible pointer type [-Wincompatible-pointer-types]

If I change e35 to (e35)(const void*)(const void*)), I get: error: expected expression before ‘const’ and error: too few arguments to function ‘e35’

If I change it to error: e35(asterisk)(const void*)(const void*)) I get: error: expected expression before ‘)’ token error: too few arguments to function ‘e35’ and error: expected expression before ‘const’

What am I missing? I believe gcc doesn't know that e35 is a function, rather than a variable or an array.

I've used qsort() before, but this is the first time under gcc. Previously, I've used it under TurboC, where all I need is the name of the function, e35.

I'm compiling using gcc under Debian Linux. The purpose of the qsort() is that I repeatedly search the table later, and want to be able to do that quicker.

(Side question, just for fun: why have I called the comparing routine e35? Where is that from and what's the significance? Perhaps I should have put this side question on either puzzing or retrocomputing instead.)

1
The function should return int, not short int. Unrelated, that's a dreadfully expensive way to compare two short values. - WhozCraig
@WhozCraig thanks. I've changed e35() to return int, not short int. I don't understand the part about comparing two short values; with the table potentially reaching hundreds of entries, wouldn't a binary search on a sorted table be faster? - Jennifer
memcmp( /* into se- */ (short int*)&((struct ELEMEN*)elem1)-> tasknum, /* quence by */ (short int*)&((struct ELEMEN*)elem2)-> tasknum, /* task number */ sizeof(short) is an byte-by-byte level sort vs a short sort. In effect endian dependent. - chux - Reinstate Monica
Your comparator. If you want to compare two short values, then compare two short values. The memcmp shenanigans are expensive, endian-dependent, and ultimately pointless. Also, your field jockying to attempt to hit TABWIDTH as the precise element size is both dangerous and assumptive. The compiler is free to perform member alignment however it wants, and qsort will happily trust whatever value you're giving it as the element size, no matter how wrong it is. use sizeof *bigtable as the element size. Regardless, I see no reason, once the rettype is fixed, that call should warn about anything. - WhozCraig
That struct is just odd. The two zero-length arrays are wtf-material if I've ever seen it. Its the reason this code is playing field-hockey with member size calculation. I understand the goal, but can't agree on the method, is all. Regardless, the retval fix on your function should address the compiler warning on the qsort call. - WhozCraig

1 Answers

0
votes

Use an int return. Drop unnecessary casts. Compare as short. Avoid subtraction overflow.

int e35(const void* elem1, const void* elem2) {
  const struct ELEMEN* t1 = elem1;
  const struct ELEMEN* t2 = elem2;
  return (t1->tasknum > t2->tasknum) - (t1->tasknum < t2->tasknum);
}