Go: convert unsafe.Pointer to function pointer and

2019-05-15 07:14发布

问题:

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.)

回答1:

As Jsor'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



回答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.