What are the parameters of this q qort function call?

qsort(bt->rw[t], bt->num[t], sizeof(TRELLIS_ATOM *), (int (*)(const void *,const void *))compare_wid); 

bt->rw[t] is a pointer to a structure pointer, bt->[num] is int , I don’t understand what the fourth parameter is, except that compare_wid is a function defined somewhere like this:

 static int compare_wid( TRELLIS_ATOM* a, TRELLIS_ATOM* b ) { ... return x; } 
+4
source share
8 answers

(int (*)(const void *,const void *)) means "consider what follows the pointer to a function that takes two parameters of type const void* and returns int ." compare_wid really is a function that can be interpreted this way.

qsort will call this function to perform comparisons between elements when sorting: if the integer that it returns is zero, it is assumed that the elements are equal, otherwise the sign of the integers is used to order them.

+5
source

I will get a little to the value of the string, but before I do this, let me get some basics of why qsort() needs its final parameter of the type it needs. qsort() is a function that can sort data of any type.

You provide it with

  • a base pointer that points to the beginning of a continuous data block,
  • the number of elements in the block,
  • the size of one data item and
  • A function that compares two data values.

Since the sorting algorithm is completely independent of the type of data being sorted, qsort() can be written without knowing which data types it sorts. But to do this, qsort() accepts void * parameters, which means a "generic pointer" in C.

Say you have an array of unsorted int values:

 #define N 1024 int data[N] = { 10, 2, 3, -1, ... } /* 1024 values */ 

Then you can sort them by calling qsort() :

 qsort(data, N, sizeof data[0], compare_int); 

data is of type int * when passed to qsort() , and the first parameter qsort() is of type void * . Since any object pointer can be converted to void * in C, this is normal. The following two arguments are fine too. The final argument to compare_int must be a function that takes two parameters const void * and returns int . The function will be called qsort() with pairs of pointers from &data[0] to &data[N-1] as many times as needed.

To declare a function f() that "takes two parameters const void * and returns int ":

 int f(const void *, const void *); 

If you want to declare a pointer to a function that we can set to f , the pointer will be declared as:

 int (*pf)(const void *, const void *); pf = f; 

Brackets are necessary because otherwise pf will be a function returning int * . Now pf is a pointer to a function that returns an int .

Returning to our int sorting algorithm, and from the above, we can define compare_int() as:

 int compare_int(const void *a, const void *b) { const int *the_a = a; const int *the_b = b; if (*the_a > *the_b) return 1; else if (*the_a < *the_b) return -1; else return 0; } 

When writing compare_int() we know that the passed int * pointers are disguised as void * , so we convert them back to int * , which is fine, and then we compare the numbers.

Now we will turn our attention to this code:

 static int compare_wid( TRELLIS_ATOM* a, TRELLIS_ATOM* b ) 

means compare_wid is a function that takes two TRELLIS_ATOM * parameters and returns int . As we just saw, the last argument to qsort() should be a function that is of type:

 int (*)(const void *, const void *) 

Ie, a function that takes two parameters const void * and returns int . Since the types do not match, the programmer distinguishes compare_wid() from the type required by qsort() .

However, this has problems. Function type:

 int (*)(TRELLIS_ATOM *, TRELLIS_ATOM *) 

not equivalent to a function like:

 int (*)(const void *, const void *) 

therefore, it will not be guaranteed if the throw works. It is much simpler, correct and standard to declare compare_wid() as follows:

 static int compare_wid(const void *a, const void *b); 

And the definition of compare_wid() should look like this:

 static int compare_wid(const void *a, const void *b) { const TRELLIS_ATOM *the_a = a; const TRELLIS_ATOM *the_b = b; ... /* Now do what you have to do to compare the_a and the_b */ return x; } 

If you do this, you won’t need translation when you call qsort() , and your program will not only be easier to read, but also correct.

If you cannot change compare_wid() , then write another function:

 static int compare_stub(const void *a, const void *b) { return compare_wid(a, b); } 

and call qsort() with compare_stub() (without translation) instead of compare_wid() .

Edit: based on many incorrect answers, here is a test program:

 $ cat qs.c #include <stdio.h> #include <stdlib.h> struct one_int { int num; }; #ifdef WRONG static int compare(const struct one_int *a, const struct one_int *b) { #else static int compare(const void *a_, const void *b_) { const struct one_int *a = a_; const struct one_int *b = b_; #endif if (a->num > b->num) return 1; else if (a->num < b->num) return -1; else return 0; } int main(void) { struct one_int data[] = { { 42 }, { 1 }, { 100 } }; size_t n = sizeof data / sizeof data[0]; qsort(data, n, sizeof data[0], compare); return 0; } 

Compiling with compare() , defined as taking two values ​​of const struct one_int * :

 $ gcc -DWRONG -ansi -pedantic -W -Wall qs.c qs.c: In function `main': qs.c:32: warning: passing argument 4 of `qsort' from incompatible pointer type 

Compilation with the correct definition:

 $ gcc -ansi -pedantic -W -Wall qs.c $ 

Editing 2: There seems to be some confusion as to the legality of using compare_wid as-it-for the final qsort() argument. comp.lang.c FAQ, question 13.9 has a good explanation (my attention):

To understand why curious pointer conversions are needed in qsort comparison functions (and why casting a function pointer when calling qsort does not help), it is useful to think about how qsort works. qsort knows nothing about the type or presentation of sorted data: it just moves around small pieces of memory. (All he knows about pieces is their size, which you specify in qsort third argument.) To determine if two pieces need to be replaced, qsort calls the comparison function. (To swap, it uses the equivalent of memcpy .)

Since qsort is common with pieces of memory of an unknown type, it uses common pointers (void *) to refer to them. When qsort calls the comparison function, it passes as arguments two common pointers to the pieces to be compared. Since it passes common pointers, your comparison function should take general pointers and convert the pointers back to the appropriate type before manipulating them (for example, before doing the comparison). The void pointer is not the same type as the structure pointer, and on some machines it may have a different size or representation (which is why these casts are necessary for correctness).

As mentioned in the FAQ, also see this .

+22
source

qsort

 void qsort ( void * base, size_t num, size_t size, int ( * comparator ) ( const void *, const void * ) ); 

comparator : a function that compares two elements. The function should follow this prototype:

int compator (const void * elem1, const void * elem2);

The function should take two parameters, which are pointers to elements cast as void *. These parameters should be discarded data type and their comparison.

The return value of this function should represent whether elem1 are considered less, equal, or greater than elem2, returning, respectively, a negative value, zero, or a positive value.

+3
source

The fourth parameter contains an explicit cast to the function pointer:

 int (*)(const void *,const void *) 
  • the int part matches the return type
  • The part (*) is the designation for the function pointer
  • part (const void *,const void *) are parameter types
+2
source
 /* Integer comparison function for use with the stdlib Qsort. */ inline int int_compare(const void *p1, const void *p2) { return ( *(int*)p1 - *(int*)p2 ); } 
0
source

This is a predicate function that is called by the qsort implementation to compare two TRELLIS_ATOM* .

-1
source

This is a custom sorting function for items of type TRELLIS_ATOM (whatever that is).

compare_wid should return something <0 if *a < *b ,> 0 if *a > *b and 0 if *a and *b logically considered equal.

-1
source

This is a quick sort function that requires a function pointer to a custom sort processing routine. Therefore, the type conversion for the parameter for the function pointer in the fourth parameter.

When the quicksort function is called, it executes a function pointer that you TRELLIS_ATOM *a to handle the sorting algorithm, that is, TRELLIS_ATOM *a and TRELLIS_ATOM *b , and then you do a comparison check between them and return 1, 0, or -1 in boolean comparison, for example:

  if (* a> * b) return 1;
 if (* a == * b) return 0;
 if (* a <* b) return -1;
-1
source

Source: https://habr.com/ru/post/1300730/


All Articles