dud3 dud3 - 1 month ago 18
C Question

C Pointers - Function pointer passed as a paramter

Problem space:

I'm having a little bit of trouble understanding the syntax of the following final parameter, which is a function pointer passed as parameter:

qsort(
(void **) lineptr, 0, nlines - 1,

/* Can't understand the following syntax */
(int (*)(void*, void*))(numberic ? numcmp : strcmp)
);


There's an alternative way that I do understand:

int (*fn)(void*, void*);
if(numeric) {
fn = numcmp;
} else {
fn = strcmp;
}


Also both of them generate compiler error:
warning: assignment from incompatible pointer type
.

Code:

#include <stdio.h>
#include <string.h>
#include "alloc.h"
#include "line.h"
#include "qsort.h"
#include "numcmp.h"

char *lineptr[MAXLINES];

int main(int argc, char *argv[])
{
int nlines; /* number of input lines read */
int numeric = 0;

if (argc > 1 && strcmp(argv[1], "-n") == 0)
numeric = 1;

if((nlines = readlines(lineptr, MAXLINES)) >= 0) {

/*
qsort with custome soring function passed as a parameter
throught pointers
*/
int (*fn)(void*, void*);
if(numeric) {
fn = numcmp;
} else {
fn = strcmp;
}

qsort((void **) lineptr, 0, nlines - 1, fn);

/*
Alternative:
qsort(
(void **) lineptr, 0, nlines - 1,
(int (*)(void*, void*))(numberic ? numcmp : strcmp)
);
*/

printf("Sorted and tailed:\n");
writelines(lineptr, nlines);

return 0;
} else {
printf("error: input to big to sort\n");
return 1;
}
}

Answer

It's essentially a cast from the result of the ternary expression to a function pointer that should the corresponding parameter in qsort. Thus, along the lines of (a)b, with b the ternary expression, and a your function pointer declaration.

int (*)(void*, void*) declares a pointer to a function that takes two void * arguments and returns an int.

Note on the (*):

  • if you remove the parentheses, you'll have a function that returns a pointer to an int.
  • with the parentheses, you have a pointer to a function that returns an int.

Spot the difference.


There is the wonderful utility cdecl that can explain such declarations. Here it is for your case:

cdecl> explain (int (*)(void*, void*))
cast unknown_name into pointer to function (pointer to void, pointer to  void) returning int

(sadly, it appears to fail when using the ternary expression: `bad character ':'. You'll have to make that part up.)

Try it out online at cdecl.org, or install it locally.

(A relevant discussion on deciphering C declarations was on Hacker News recently, where alternatives to the clockwise/spiral rule are mentioned.)