how do I pass a generic comparison function?

A

aurgathor

Howdy,

How do I pass some function a generic comparison
function? I figured out one non-generic case, but
since this code got parameter declarations in two places,
it's obviously not generic.

TIA

#include <stdio.h>

char comp1 ( int, int );
char comp2 ( char, char );
char comp3 ( char*, char* );

char comp1 ( int i1, int i2 ) {
if (i1 == i2) {
return '=';
} else if (i1 > i2) {
return '>';
} else {
return '<';
}
}

/* comp2 & comp3 omitted for brevity */

int some_func ( char (*comp)(int,int)) {
putchar((*comp) (7,8));
putchar((*comp) (8,8));
putchar((*comp) (8,7));
return 0;
}

int main () {
int i;
i = some_func((char (*)(int, int))(comp1));
return 0;
}
 
J

Jens.Toerring

aurgathor said:
How do I pass some function a generic comparison
function? I figured out one non-generic case, but
since this code got parameter declarations in two places,
it's obviously not generic.
#include <stdio.h>
char comp1 ( int, int );
char comp2 ( char, char );
char comp3 ( char*, char* );
char comp1 ( int i1, int i2 ) {
if (i1 == i2) {
return '=';
} else if (i1 > i2) {
return '>';
} else {
return '<';
}
}
/* comp2 & comp3 omitted for brevity */
int some_func ( char (*comp)(int,int)) {
putchar((*comp) (7,8));
putchar((*comp) (8,8));
putchar((*comp) (8,7));
return 0;
}
int main () {
int i;
i = some_func((char (*)(int, int))(comp1));
return 0;
}

Did you have a look at how it's done with the qsort() function? It
expects (as it's fourth argument) a function that has two 'const
void *' arguments. And I guess that's the only way to make the
function as generic as possible, i.e. you can pass all kinds of
data types to the comparison functions that way. If you use that
you would have something like

#include <stdio.h>

char cmp_as_ints( const void *a, const void *b ) {
if ( * ( int * ) a == * ( int * ) b )
return '=';
else if ( * ( int * ) a < * ( int * ) b )
return '<';
return '>';
}

int some_func( char ( *cmp )( const void *, const void * ) ) {
int dummy1 = 7, dummy2 = 8;
putchar( cmp( &dummy1, &dummy2 ) );
dummy1 = 8;
putchar( cmp( &dummy1, &dummy2 ) );
dummy2 = 7;
putchar( cmp( &dummy1, &dummy2 ) );
return 0;
}

int main( void ) {
int i = some_func( cmp_as_ints );
return 0;
}

Since you have to pass pointers to the comparison function you unfor-
tunately need two dummy variables in some_func() to be able to pass
their addresses. BTW, when you call a function via a function pointer
you can but don't have to dereference the function pointer, so both

cmp( &var1, &var2 )

and

( * cmp )( &var1, &var2 )

are perfectly valid ways to call the function 'cmp' points to.

Regards, Jens
 
C

CBFalconer

aurgathor said:
How do I pass some function a generic comparison
function? I figured out one non-generic case, but
since this code got parameter declarations in two places,
it's obviously not generic.

#include <stdio.h>

char comp1 ( int, int );
char comp2 ( char, char );
char comp3 ( char*, char* );

char comp1 ( int i1, int i2 ) {
if (i1 == i2) {
return '=';
} else if (i1 > i2) {
return '>';
} else {
return '<';
}
}

/* comp2 & comp3 omitted for brevity */
int some_func ( char (*comp)(int,int)) {
putchar((*comp) (7,8));
putchar((*comp) (8,8));
putchar((*comp) (8,7));
return 0;
}

int main () {
int i;
i = some_func((char (*)(int, int))(comp1));
return 0;
}

You use void *. To compare ints:

int cmpint(void *left, void *right)
{
int *leftitem = left;
int *rightitem = right;

if (leftitem > rightitem) return '>';
else if (leftitem < rightitem) return '<';
else return '=';
|

and functions to compare other types need only vary the name and
the types of the local pointers. The calling will only vary the
name of the function passed:

typedef int cmpfunct(void *, void *);

void foo(cmpfunct cmp)
{
... cmp(leftthing, rightthing);
}

....
foo(cmpint);
 
M

Michael

You use void *. To compare ints:

int cmpint(void *left, void *right)
{
int *leftitem = left;
int *rightitem = right;

if (leftitem > rightitem) return '>';
else if (leftitem < rightitem) return '<';
else return '=';
|
should this not be
if( *leftitem > *rightitem) return '>';
or am i overlooking something??

Regards

Mike
 
C

CBFalconer

Michael said:
should this not be
if( *leftitem > *rightitem) return '>';
or am i overlooking something??

Yes and no respectively. The dog ate the asterisks.
 
D

Dave Thompson

Howdy,

How do I pass some function a generic comparison
function? I figured out one non-generic case, but
since this code got parameter declarations in two places,
it's obviously not generic.
char comp1 ( int, int );
char comp2 ( char, char );
char comp3 ( char*, char* );
int some_func ( char (*comp)(int,int)) {
<snip: use (*comp)( 2 ints )>

Several others have given specific answers using void*. That's usually
the simplest way but not the only one. What matters is that type of
parameters declared by the routine is the same as that declared to the
code that does the call (here through a pointer passed as parameter).

For scalar types there are hierarchies where a 'higher' type can
(always) handle the values of a 'lower' one, which you can then
convert/cast back if and when desired. For example long can handle any
int and int any short, and short any char if char is signed always and
even unsigned on 'normal' (8-bit) machines. double can handle any
float. void * (perhaps qualified) can handle any data pointer; so can
char * but it doesn't convert silently.

More generally but clumsily, you can create and use a union type. This
requires creating dummy objects at the point of 'anonymization' in
C90; in C99 you can use a compound literal, and in GCC as an extension
you can just cast to a union type that has a suitable member. This
does require that all types to be used be known at coding time; with
void * you can later (maybe even dynamically) add (instances of) new
types that pass through unchanged middle code.

- David.Thompson1 at worldnet.att.net
 
D

Developper

Dave Thompson said:
<snip: use (*comp)( 2 ints )>

Several others have given specific answers using void*. That's usually
the simplest way but not the only one. What matters is that type of
parameters declared by the routine is the same as that declared to the
code that does the call (here through a pointer passed as parameter).

For scalar types there are hierarchies where a 'higher' type can
(always) handle the values of a 'lower' one, which you can then
convert/cast back if and when desired. For example long can handle any
int and int any short, and short any char if char is signed always and
even unsigned on 'normal' (8-bit) machines. double can handle any
float. void * (perhaps qualified) can handle any data pointer; so can
char * but it doesn't convert silently.

More generally but clumsily, you can create and use a union type. This
requires creating dummy objects at the point of 'anonymization' in
C90; in C99 you can use a compound literal, and in GCC as an extension
you can just cast to a union type that has a suitable member. This
does require that all types to be used be known at coding time; with
void * you can later (maybe even dynamically) add (instances of) new
types that pass through unchanged middle code.

- David.Thompson1 at worldnet.att.net

you cannot

The best thing you can do is using char * and use strcmp I think

Johan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,160
Messages
2,570,889
Members
47,421
Latest member
StacyTaver

Latest Threads

Top