Wednesday, December 7, 2011

How to return a function pointer without a typedef in C/C++

The intertubes are full of examples on how to use function pointers in C/C++. Most try to simplify things by typedef'ing the function signature. What if you're a glutton for punishment like me and want to do it the "hard" way?

Ok, here's the background. Let's say you want to be able to find the cosine of an array of doubles, but you also want to be able to find the sine, tangent, etc.

You could do this:
#include <math.h>

void apply_sin(double *dat, int length, int type)
{
    int k;
    for (k=0;k<length;k++)
    {
        dat[k] = sin(dat[k]);
    }
}

void apply_cos(double *dat, int length, int type)
{
    int k;
    for (k=0;k<length;k++)
    {
        dat[k] = cos(dat[k]);
    }
}

void apply_tan(double *dat, int length, int type)
{
    int k;
    for (k=0;k<length;k++)
    {
        dat[k] = tan(dat[k]);
    }
}

void apply_square(double *dat, int length, int type)
{
    int k;
    for (k=0;k<length;k++)
    {
        dat[k] *= dat[k];
    }
}


But this leaves a lot to be desired. Each operation requires a new function that is nearly identical to all the rest. Can't we factor out the commonality?

Ok, how about this:

#include <math.h>
#include <stdio.h>

double square(double val)
{
    return val * val;
}

void apply_operation(double *dat, int length, double (*oper)(double))
{
    int k;
    for (k=0;k<length;k++)
    {
        dat[k] = oper(dat[k]);
    }
}

void print_vector(double *dat, int length)
{
    int k;
    for (k=0;k<length;k++)
    {
        printf("%g ", dat[k]);
    }
    printf("\n");
}

void call_it(void)
{
    double vals[] = {1,2,3};
    apply_operation(vals, sizeof(vals)/sizeof(vals[0]), sin);

    print_vector(vals, sizeof(vals)/sizeof(vals[0]));
    apply_operation(vals, sizeof(vals)/sizeof(vals[0]), cos);
    print_vector(vals, sizeof(vals)/sizeof(vals[0]));
    apply_operation(vals, sizeof(vals)/sizeof(vals[0]), tan);

    print_vector(vals, sizeof(vals)/sizeof(vals[0]));
    apply_operation(vals, sizeof(vals)/sizeof(vals[0]), square);
    print_vector(vals, sizeof(vals)/sizeof(vals[0]));
}

int main(int argc, char *argv[])
{
    call_it();
}


So that's a bit better. Only one implementation of the loop code, simple implementations for each operation, only the overhead of an additional pointer dereference per element. How did we pull this off?

void apply_operation(double *dat, int length, double (*oper)(double))


apply_operation() takes a function pointer as a parameter (the last argument). This makes it so that apply_operation() can take any function that takes a single double as input and returns a single double as output. Slick.

Now, the next step: returning a function pointer (without typedefing the signature). Let's say we have a table of operations and we associate each operation type with a function pointer so that we can do a simple lookup to get a pointer to the desired operation function. So, in other words, we're returning a function pointer. Here's how to do it without a typedefed function signature.

#include <math.h>
#include <stdio.h>

enum
{
    OPER_SIN,
    OPER_COS,
    OPER_TAN,
    OPER_SQUARE
};

struct oper
{
    int type;
    double (*func)(double);
};

double square(double val)
{
    return val * val;
}

struct oper oper_lut[] =
{
    {OPER_SIN, sin},
    {OPER_COS, cos},
    {OPER_TAN, tan},
    {OPER_SQUARE, square},

};

double (*get_oper(int oper_type))(double)
{
    int n;
    for (n=0;n<(sizeof(oper_lut)/sizeof(oper_lut[0]));n++)
    {
        if (oper_type == oper_lut[n].type)
        {
            return oper_lut[n].func;
        }
    }
}

void apply_operation(double *dat, int length, double (*oper)(double))
{
    int k;
    for (k=0;k<length;k++)
    {
        dat[k] = oper(dat[k]);
    }
}

void print_vector(double *dat, int length)
{
    int k;
    for (k=0;k<length;k++)
    {
        printf("%g ", dat[k]);
    }
    printf("\n");
}

void call_it(void)
{
    double vals[] = {1,2,3};
    double (*func)(double);
    func = get_oper(OPER_SIN);
    apply_operation(vals, sizeof(vals)/sizeof(vals[0]), func);
    print_vector(vals, sizeof(vals)/sizeof(vals[0]));
    func = get_oper(OPER_COS);
    apply_operation(vals, sizeof(vals)/sizeof(vals[0]), func);
    print_vector(vals, sizeof(vals)/sizeof(vals[0]));
    func = get_oper(OPER_TAN);
    apply_operation(vals, sizeof(vals)/sizeof(vals[0]), func);
    print_vector(vals, sizeof(vals)/sizeof(vals[0]));
    func = get_oper(OPER_SQUARE);
    apply_operation(vals, sizeof(vals)/sizeof(vals[0]), func);
    print_vector(vals, sizeof(vals)/sizeof(vals[0]));
}

int main(int argc, char *argv[])
{
    call_it();
}


The magic is in get_oper(). Did you catch it?

double (*get_oper(int oper_type))(double)


This means that get_oper() is a function that takes a single int as a parameter and returns a function pointer to a function that returns a double and takes a single double as its only argument. Simple, right? There it is--returning a function pointer from a function without typedefing the signature (the "hard" way).

This is the best reference I've seen so far on function pointers http://www.newty.de/fpt/fpt.html.

Wednesday, March 3, 2010

Surviving Visual Studio

I love emacs. I can't describe how much I miss it when I have to do development in Windows. Yes, I know there's a version of emacs for Windows, but it seems like if you're developing for Windows it's easier to give into the borg than to fight them.
My tip for the day:
C-k C-f indents a region similar to C-M-\ in emacs.

Sunday, October 19, 2008

Now the Economic Crisis is Personal ... Mother's Cookie Company Goes Out of Business

The economic crisis hasn't really made a big difference in my life until today. I just heard that Mother's Cookie Company is going under. I bought one last bag of pink and white "Circus Animals". Apparently it will have to last me for ETERNITY. Where's the 700 billion dollar bailout for cookie companies? Forget the whales, SAVE THE COOKIES! Check out the AP story.

Thursday, August 14, 2008

gtk.FileChooserDialog() mini-HOWTO

Enough is enough! It seems like every time I write a pygtk app I end up needing a file chooser dialog yet every time I can't remember the details. The reference page for gtk.FileChooserDialog() is excellent--for reference. I need a gtk.FileChooserDialog() mini-HOWTO. Here it is:

fc = gtk.FileChooserDialog(title='Open File...',
                                   parent=None,
                                   action=gtk.FILE_CHOOSER_ACTION_OPEN,
                                   buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK))
        fc.set_current_folder(g_directory)
        fc.set_default_response(gtk.RESPONSE_OK)
        filter = gtk.FileFilter()
        filter.set_name('Audio Files')
        filter.add_pattern('*.wav')
        filter.add_pattern('*.mp3')
        filter.add_pattern('*.flac')
        fc.add_filter(filter)
        response = fc.run()
        if response == gtk.RESPONSE_OK:
            print 'ok'
            print fc.get_filename()
            self.entry.set_text(fc.get_filename())
            g_directory = fc.get_current_folder()
        else:
            print 'not ok'
        fc.destroy()
There, done! This page is also an excellent, more complete, example.

Wednesday, June 25, 2008

I knew I Could Do Better

After brushing up on the periodic table, and embellishing my education a little ... I am nerdier than 100% of all people. Are you a nerd? Click here to find out! Beat that!

Mindless Drivel, but Entertaining Nonetheless

I am nerdier than 94% of all people. Are you a nerd? Click here to find out!

Saturday, April 12, 2008

Review of "King of Kong: A Fist Full of Quarters"

Over the last three days (it's been several months ago now) I've had the extreme pleasure of watching "King Kong: A Fist Full or Quarters". You must see this movie.

It is, in my opinion, the quintessential American underdog story set to the music of Donkey Kong. On one side you have Billy Mitchell, a superstar in his own world. Arguably the best gamer of all time, but certainly the best classic gamer of all time. Billy is amazing--He's truly gifted. Unfortunately, like a lot of us in this world, his head is much bigger than it aught to be. (In Billy's case, his hair is longer than it aught to be too.)

On the other side you have Steve Wiebe, an apparent "screw up" (and I mean that in the nicest way possible). Of his own admission, he hasn't lived up to his true potential throughout his live. Highly athletic yet subject to "the chokes", gifted musically but prohibitively shy, highly intelligent yet awkward and sheepish.

"King of Kong: A Fist Full of Quarters" is their story.

I won't spoil the rest, but I will say this: be prepared for the subculture of classic gaming's superstars, groupies, officials, desperate wannabees, outsiders, insiders, family members, winners, and losers. It's a strange world, beyond description, even for a geek like me. After you've watched the movie, go check out the current record at Twin Galaxies.