3

In C you can put function pointers into an array of void pointers and convert them back to function pointers of any type:

extern int (*fn1)(void);
extern void (*fn2)(int);
void foo(void)
{
        void *array[2];
        int i;

        /* implicit cast from function pointer to void pointer */
        array[0] = fn1;
        array[1] = fn2;
        for (i = 0; i < 2; i++)
        {
                int (*fp)(int, int, int);

                /* implicit cast from void pointer to function pointer */
                fp = array[i];
                /* call function with a different signature */
                fp(1, 2, 3);
        }
}

I need to do the same in Go, using unsafe.Pointers. The questions are:

  • Can a Go function pointer be converted to an unsafe.Pointer?
  • Can an unsafe.Pointer be converted to a Go function pointer of a different (or the same) type as the original function pointer?

(The question is not why or whether I need to do that; in the given situation it is okay to call a function with the wrong set of parameters and to misinterpret the return value because the caller and the callees are able to deal with that.)

user3510167
  • 303
  • 3
  • 8
  • I answered: yes it works, though I have to admit I am incredibly curious about why you need to do this. – Linear Apr 08 '14 at 09:57
  • Because I'm working on the gofrontend in gccgo and need to generate artificial code in tree representation that calls multiple functions from exactly the same address. I'm not really writing Go code, but if I can stick with the classes for parsing Go source code that are already in the frontend, it's much less work. – user3510167 Apr 08 '14 at 10:50
  • You can't do that in C. That's undefined behavior and a good compiler should warn you. function pointers are incompatible to data pointer for a series of very good reasons. – fuz Apr 10 '14 at 14:40

2 Answers2

3

As LinearZoetrope's answer shows, you can do this. Beware that you can do bad things:

package main

import (
    "fmt"
    "unsafe"
)

func main() {
    f1 := func(s string) {}
    f2 := func(i int) int { return i + 1 }
    pointers := []unsafe.Pointer{
        unsafe.Pointer(&f1),
        unsafe.Pointer(&f2),
    }
    f3 := (*func(int) bool)(pointers[1]) // note, not int
    fmt.Println((*f3)(1))
}

playground

Linear
  • 21,074
  • 4
  • 59
  • 70
mjibson
  • 16,852
  • 8
  • 31
  • 42
2

It appears to work:

package main

import (
    "fmt"
    "unsafe"

    "math"
)

func main() {
    fn := print
    faked := *(*func(float64))(unsafe.Pointer(&fn))
    faked(1.0)

    // For comparison
    num := math.Float64bits(1.0)
    print(num)
}

func print(a uint64) {
    fmt.Println(a)
}

Will print

4607182418800017408

4607182418800017408

Of course, you're probably well aware of the potential problems with trying this.

Community
  • 1
  • 1
Linear
  • 21,074
  • 4
  • 59
  • 70