4
\$\begingroup\$

My question is about this sort of table that's simplified here. Often, I find myself putting this element, (int (*)(const void *, const void *))&strcmp for bsearch. I go between prototyping with void pointers, creating dummy functions, and casting, but none is really a satisfactory, especially when the functions are complex.

#include <stdlib.h>
#include <stdio.h>

static void number(int *const);
static void letter(char *const);

static void (*const action[])(void *const) = {
    (void (*)(void *))&number,
    (void (*)(void *))&letter
};

/* corresponds to the 'action' index */
enum Type { NUMBER = 0, LETTER = 1 };

struct Thing {
    enum Type type;
    void *data;
};

int main(void) {
    const char aah  = 'a';
    const int  five = 5;
    const int  six  = 6;
    const struct Thing things[] = {
        { LETTER, (void *)&aah },
        { NUMBER, (void *)&five },
        { NUMBER, (void *)&six }
    };
    const int things_size = sizeof things / sizeof(struct Thing);
    const struct Thing *t;

    /* prints a 5 6 */
    for(t = things; t < things + things_size; t++) {
        action[t->type](t->data);
    }

    return EXIT_SUCCESS;
}

static void number(int *const dp) {
    printf("%d\n", *dp);
}

static void letter(char *const cp) {
    printf("%c\n", *cp);
}

This https://stackoverflow.com/questions/559581/casting-a-function-pointer-to-another-type/559671#559671 seems to suggest that it's dubious to do this. What is the cleanest, most correct way to achieve this sort of polymorphism?

\$\endgroup\$
1
\$\begingroup\$

This doesn't really answer your question, but when using function pointers it is usually easier to use a typedef:

typedef void (*Action) (void * const);
static Action action[] = { (Action) number, (Action) letter };

Also the calling of the action would be better expressed as

struct Thing {
    Action action;
    void *data;
};
...
const struct Thing things[] = {
    { (Action) letter, (void *)&aah },
    { (Action) number, (void *)&five },
    { (Action) number, (void *)&six }
};
for(t = things; t < things + things_size; t++) {
    t->action(t->data);
}
\$\endgroup\$
  • \$\begingroup\$ Improves abstraction and is certainly more readable. \$\endgroup\$ – Neil Jul 1 '16 at 3:36
  • \$\begingroup\$ I used this style and I really like it; in the style of link. I'm accepting this answer because it cleans up the code so well. \$\endgroup\$ – Neil Jul 13 '16 at 22:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.