qsort() syntax not clear

Please consider the invocation of the qsort() function in the following example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
   #include <cstdlib>			/// qsort()
   #include <cstring>			/// strcmp()


   void f()
   {
      const char* as[] = {"Jack", "Joe", "Jill"};

      qsort(as,				/// array to sort
            sizeof(as) / sizeof(*as),	/// number of elements in the array
            sizeof(*as),		/// size of each array element
            (int (*) (const void*, const void*)) strcmp;
           );
   }


The qsort() function takes 4 parameters. I am clear about the first 3.

However, I find the syntax of the 4th parameter a bit confusing:

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


I interpret this as follows (rightly or wrongly):
1) strcmp is a pointer to a function of that name.
2) The expression to its left is a cast.
3) This expression denotes a pointer to a function that takes 2 const void*s as parameters and returns an int.
4) Therefore the entire expression casts a pointer to strcmp to the above pointer type.

And frankly, this doesn't make sense.

What's the correct meaning here?

Thanks.
> I interpret this as follows (rightly or wrongly):
> 1) strcmp is a pointer to a function of that name.
> 2) The expression to its left is a cast.
> 3) This expression denotes a pointer to a function that takes 2 const void*s as parameters and returns an int.
> 4) Therefore the entire expression casts a pointer to strcmp to the above pointer type.

Yes.

The cast is required because the standard C library qsort expects a pointer to a function
with type int( const void*, const void* )

std::qsort in the standard C++ library is more flexible; however the semantics of the compare function
(which may be any callable object) is the same as that required by the C library.

The semantics are annotated via comments in this snippet:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>
#include <cstdlib>
#include <iterator>

int main()
{
    int arr[] { 11, 24, 17, 21, 14, 12, 10, 19, 23, 22, 13, 20, 16, 15, 18 } ;
    for( int v : arr ) std::cout << v << ' ' ;
    std::cout << '\n' ;

    // callable object called by std::qsort to compare elements being sorted
    // its signature must be equivalent to int( const void*, const void* )
    // ie. it accepts two arguments of type const void* and returns int
    // if it is a pointer to a free function, it may have either C or C++ linkage.
    const auto cmp_int = [] ( const void* pa, const void* pb  )
    {
        // the two arguments pa and pb are pointers to the two elements to be compared
        // if the comparison function modifies either of the two objects,
        // it would engender undefined behaviour.

        // we know that we are using this compare function to sort an array of int
        // get the values of the integers to be compared (via compile-time casts)
        const int a = *static_cast< const int* >(pa) ;
        const int b = *static_cast< const int* >(pb) ;

        // this compare function must return:
        //
        // ​a negative integer value if the element identified by the first argument
        // should appear before the element identified by the second argument in the sorted sequence
        // (in our case, for sort in ascending order, if a < b )
        //
        // ​a positive integer value if the element identified by the first argument
        // should appear after the element identified by the second argument in the sorted sequence
        // (in our case, for sort in ascending order, if a > b )
        //
        // zero if the the element identified by the first argument may appear either before
        // or after the element identified by the second argument in the sorted sequence
        // (in our case, for sort in ascending order, if a == b )
        return (a>b) - (b>a) ;
    };

    std::qsort( std::begin(arr), sizeof(arr)/sizeof(arr[0]), sizeof(int), cmp_int ) ;
    for( int v : arr ) std::cout << v << ' ' ;
    std::cout << '\n' ;
}

http://rextester.com/NXWO12751
Last edited on
More qsort() examples:

http://www.cplusplus.com/faq/sequences/sequencing/sort-stuff/#c

(I need to fix the FAQ to remove that randomize example -- it is not correct, so ignore it. :] .)
Forgot to mention it earlier; in theory, this engenders undefined behaviour.
1
2
3
4
5
std::qsort( as,				/// array to sort
            sizeof(as) / sizeof(*as),	/// number of elements in the array
            sizeof(*as),		/// size of each array element
            (int (*) (const void*, const void*)) strcmp;
           );

(Calling a function through a pointer to a function type that is not identical to the type with which the function is defined engenders undefined behaviour. Though, in practice, this particular piece of code would work predictably in the manner expected by the programmer.)
Topic archived. No new replies allowed.