第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

使用 cgo 將函數(shù)指針傳遞給 C 代碼

使用 cgo 將函數(shù)指針傳遞給 C 代碼

Go
喵喵時光機 2022-01-10 14:58:54
從 Go v1.6 開始,cgo 更改了將指針傳遞給 C 代碼golang/go#12416 的規(guī)則。從 wiki 的 C 代碼調用動態(tài) Go 回調的示例不再有效。package mainimport (    "fmt"    "unsafe")/*   extern void go_callback_int(void* foo, int p1);   // normally you will have to define function or variables   // in another separate C file to avoid the multiple definition   // errors, however, using "static inline" is a nice workaround   // for simple functions like this one.   static inline void CallMyFunction(void* pfoo) {       go_callback_int(pfoo, 5);       }*/import "C"//export go_callback_intfunc go_callback_int(pfoo unsafe.Pointer, p1 C.int) {    foo := *(*func(C.int))(pfoo)    foo(p1)}func MyCallback(x C.int) {    fmt.Println("callback with", x)}// we store it in a global variable so that the garbage collector// doesn't clean up the memory for any temporary variables created.var MyCallbackFunc = MyCallbackfunc Example() {    C.CallMyFunction(unsafe.Pointer(&MyCallbackFunc))}func main() {    Example()}輸出如下所示:panic: runtime error: cgo argument has Go pointer to Go pointer今天這樣做的正確方法是什么?最好不要像通過將指針轉換為 uintptr_t 來隱藏語言中的指針這樣的技巧。
查看完整描述

3 回答

?
當年話下

TA貢獻1890條經(jīng)驗 獲得超9個贊

從 Go 1.6 開始,cgo 有了新的規(guī)則。


Go 代碼可以將 Go 指針傳遞給 C,前提是它指向的 Go 內存不包含任何 Go 指針。


在運行時檢查這些規(guī)則,如果違反程序崩潰。目前可以使用GODEBUG=cgocheck=0環(huán)境變量禁用檢查。但在未來,這可能會停止工作。


因此,如果指針指向的內存存儲了 Go 函數(shù)/方法指針,則無法再將指針傳遞給 C 代碼。有幾種方法可以克服這個限制,但我想在大多數(shù)方法中你應該存儲一個同步的數(shù)據(jù)結構,它表示某個 id 和實際指針之間的對應關系。這樣,您可以將 id 傳遞給 C 代碼,而不是指針。


解決此問題的代碼可能如下所示:


package gocallback


import (

    "fmt"

    "sync"

)


/*

extern void go_callback_int(int foo, int p1);


// normally you will have to define function or variables

// in another separate C file to avoid the multiple definition

// errors, however, using "static inline" is a nice workaround

// for simple functions like this one.

static inline void CallMyFunction(int foo) {

    go_callback_int(foo, 5);

}

*/

import "C"


//export go_callback_int

func go_callback_int(foo C.int, p1 C.int) {

    fn := lookup(int(foo))

    fn(p1)

}


func MyCallback(x C.int) {

    fmt.Println("callback with", x)

}


func Example() {

    i := register(MyCallback)

    C.CallMyFunction(C.int(i))

    unregister(i)

}


var mu sync.Mutex

var index int

var fns = make(map[int]func(C.int))


func register(fn func(C.int)) int {

    mu.Lock()

    defer mu.Unlock()

    index++

    for fns[index] != nil {

        index++

    }

    fns[index] = fn

    return index

}


func lookup(i int) func(C.int) {

    mu.Lock()

    defer mu.Unlock()

    return fns[i]

}


func unregister(i int) {

    mu.Lock()

    defer mu.Unlock()

    delete(fns, i)

}

此代碼來自(更新的)wiki 頁面。


查看完整回答
反對 回復 2022-01-10
?
眼眸繁星

TA貢獻1873條經(jīng)驗 獲得超9個贊

解決方案分為三個部分。

  1. //export在 Go 函數(shù)上使用注釋告訴cgo工具為其生成 C 包裝器 ( https://pkg.go.dev/cmd/cgo#hdr-C_references_to_Go )。

  2. cgoC 序言中前向聲明該 C 標識符,以便您可以在 Go 代碼 ( https://golang.org/issue/19837 ) 中引用 C 包裝器。

  3. 使用 Ctypedef將該指針轉換為正確的 C 類型,解決一個cgo錯誤 ( https://golang.org/issue/19835 )。

把它們放在一起:

package main


/*

static void invoke(void (*f)()) {

    f();

}


void go_print_hello();  // https://golang.org/issue/19837


typedef void (*closure)();  // https://golang.org/issue/19835

*/

import "C"


import "fmt"


//export go_print_hello

func go_print_hello() {

    fmt.Println("Hello, ?!")

}


func main() {

    C.invoke(C.closure(C.go_print_hello))

}


查看完整回答
反對 回復 2022-01-10
?
慕容3067478

TA貢獻1773條經(jīng)驗 獲得超3個贊

這完全取決于您需要對回調函數(shù)執(zhí)行什么操作 - 但一個可能有效的技巧是不傳遞 Go 函數(shù),而是傳遞一個指向帶有您想要的函數(shù)的結構的指針。


例如:


package main


import (

    "fmt"

    "unsafe"

)


/*

extern void go_callback_int(void*, int);

static inline void CallMyFunction(void* pfoo) {

    go_callback_int(pfoo, 5);

}

*/

import "C"


//export go_callback_int

func go_callback_int(pfoo unsafe.Pointer, p1 C.int) {

    foo := (*Test)(pfoo)

    foo.cb(p1)

}


type Test struct {

}


func (s *Test) cb(x C.int) {

    fmt.Println("callback with", x)

}


func main() {

    data := &Test{}

    C.CallMyFunction(unsafe.Pointer(&data))

}

另一種選擇可能是使用示例中的全局變量,然后放棄在指向 C 的指針中傳遞任何有用的內容。


像這樣:


package main


import (

    "fmt"

    "unsafe"

)


/*

extern void go_callback_int(void*, int);

static inline void CallMyFunction(void* pfoo) {

    go_callback_int(pfoo, 5);

}

*/

import "C"


//export go_callback_int

func go_callback_int(_ unsafe.Pointer, p1 C.int) {

    MyCallbackFunc(p1)

}


func MyCallback(x C.int) {

    fmt.Println("callback with", x)

}


// we store it in a global variable so that the garbage collector

// doesn't clean up the memory for any temporary variables created.

var MyCallbackFunc = MyCallback


func main() {

    C.CallMyFunction(nil)

}

這可能取決于您的 C 回調需要做什么。


如果這些都不起作用,則可以使用通道做一些技巧來發(fā)送您需要的值(并將其保持在范圍內)。


查看完整回答
反對 回復 2022-01-10
  • 3 回答
  • 0 關注
  • 630 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網(wǎng)微信公眾號