Go:将`unsafe.Pointer`转换为函数指针,反之亦然。

huangapple go评论82阅读模式
英文:

Go: convert unsafe.Pointer to function pointer and vice versa

问题

在C语言中,你可以将函数指针放入一个void指针数组中,并将它们转换回任何类型的函数指针:

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

    /* 将函数指针隐式转换为void指针 */
    array[0] = fn1;
    array[1] = fn2;
    for (i = 0; i < 2; i++)
    {
        int (*fp)(int, int, int);

        /* 将void指针隐式转换为函数指针 */
        fp = array[i];
        /* 使用不同签名调用函数 */
        fp(1, 2, 3);
    }
}

我需要在Go语言中使用unsafe.Pointer来实现相同的功能。问题如下:

  • Go语言的函数指针能否转换为unsafe.Pointer
  • unsafe.Pointer能否转换回与原始函数指针类型不同(或相同)的Go函数指针?

(问题不是为什么或是否需要这样做;在给定的情况下,以错误的参数调用函数并误解返回值是可以接受的,因为调用方和被调用方能够处理这种情况。)

英文:

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 &lt; 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

得分: 3

如LinearZoetrope的答案所示,你可以这样做。请注意,你可以做一些不好的事情:

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]) // 注意,不是int
	fmt.Println((*f3)(1))
}

playground

英文:

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

package main

import (
	&quot;fmt&quot;
	&quot;unsafe&quot;
)

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

playground

答案2

得分: 2

看起来它是可以工作的:

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

将会打印:

4607182418800017408

4607182418800017408

当然,你可能非常清楚尝试这样做可能会带来的潜在问题。

英文:

It appears to work:

package main

import (
    &quot;fmt&quot;
    &quot;unsafe&quot;

    &quot;math&quot;
)

func main() {
    fn := print
    faked := *(*func(float64))(unsafe.Pointer(&amp;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.

huangapple
  • 本文由 发表于 2014年4月8日 17:39:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/22933169.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定