tags:

views:

408

answers:

5

I'm having trouble compiling the example program presented in section 5.11 of the book. I have removed most of the code and left only the relevant stuff.

#define MAXLINES 5000
char *lineptr[MAXLINES];

void qsort1(void *lineptr[], int left, int right, int (*comp)(void *, void *));
int numcmp(char *, char *);

main(int argc, char *argv[]) {
    int numeric = 1;
    /* ... */
    qsort1((void**) lineptr, 0, 100, (int (*)(void*, void*))(numeric ? numcmp : strcmp));
}

void qsort1(void *v[], int left, int right, int (*comp)(void *, void *)) {
    /* ... */
}

int numcmp(char *s1, char *s2) {
    /* ... */
}

The problem is that the code doesn't compile (I'm using Digital Mars compiler). The error I get is this:

        qsort1((void**) lineptr, 0, nlines - 1, (int (*)(void*, void*))(numeric
? numcmp : strcmp));

                 ^
go.c(19) : Error: need explicit cast to convert
from: int (*C func)(char const *,char const *)
to  : int (*C func)(char *,char *)
--- errorlevel 1

There must be something wrong with the declarations although I pasted the code from the book correctly. I don't know enough to make the right changes (the section about the function pointers could certainly have been written more extensively).

EDIT: I should have mentioned that I'm reading the ANSI version of the book.

A: 

Its been awhile since I have done any pure C programming, I'm not certain on the new standard.

However casting to void ** creates a pointer to a pointer where the function requires a pointer to an array. Sure, they are the same thing internally, but strong typechecking will catch that as an error.

rewrite the qsort to accept ** instead of *[] and you should be ok.

gbrandt
well he already accepts ** . *foo[] in a function prototype will give it the same type as **foo :) that is not teh error but it is often mistaken by programmers
Johannes Schaub - litb
+2  A: 

The standard function pointer expected by qsort() or bsearch() has the prototype:

int comparator(const void *v1, const void *v2);

The qsort1() defined in the code expects:

int comparator(void *v1, void *v2);

The comparator functions defined in the code do not have that prototype, and there is no automatic conversion between different function pointer types.

So, fixes for qsort1() are either:

  1. Introduce a cast: (int (*)(void *, void *)), or
  2. Rewrite the comparators:

    int numcmp(void *v1, void *v2)
    {
        char *s1 = v1;
        char *s2 = v2;
        ...
    }
    
    
    int str_cmp(void *v1, void *v2)  // Note new function name!
    {
        return(strcmp(v1, v2));
    }
    

Obviously, the call to qsort1() would reference str_cmp instead of strcmp. The authors sought to avoid an intermediate function, but run foul of the (legitimately) fussier compilers in use nowadays.

The standard version of qsort() would require a bunch of const qualifiers, as in the first version of this answer.

Jonathan Leffler
He is using a custom function called qsort().
dirkgently
Well, yes: qsort1() to be pedantically pedantic. And that qsort1() has a different expectations; I'll edit.
Jonathan Leffler
+2  A: 

That's a common problem :)

The following line tells qsort to expect a pointer to a function with two void* parameters. Unfortunately, strcmp takes two non-modifiable strings hence it's signature is

int (*comp)(const char*, const char*)

instead of what you have:

int (*comp)(void *, void *)

Change the signature of both qsort1 and numeric:

qsort1(void *v[], int left, int right, int (*comp)(const void *, const void *))

and:

int numcmp(const char*, const char*)
dirkgently
The signature of qsort1() you wrote is already identical to the one in my example.
Ree
I realised that about a minute and a half before you ;)
dirkgently
+3  A: 

I think the error comes from the fact that old C did not know const yet: strcmp there took two pointers to non-const characters (char *) i think (which could be the reason why it compiled back then, but not with your compiler). However, nowadays strcmp takes char const* (const char* is the same thing). Change your function prototype to this:

int numcmp(char const*, char const*);
Johannes Schaub - litb
qsort1() signature needs to change too ;)
dirkgently
indeed there is many stuff to worry about. he should give numcmp's parameters void*, void* instead of pointer to char. but he wanted to get the example from the book to compile. i didn't want to change the whole code of the book's example
Johannes Schaub - litb
+1  A: 

Note that strcmp takes two const arguments, whereas your numcmp does not. Therefore, the two functions' types do not match, and the ? : operator will complain.

Do one of:

  1. change numcmp to match the strcmp prototype in terms of constness
  2. push the (int (*)(void*, void*)) cast inside the ? :, e.g.

    numeric ? (int (*)(void*, void*))numcmp : (int (*)(void*, void*))strcmp
    

Cheers, V.

vladr