"إذا أراد العامل أن يؤدي عمله بشكل جيد، فعليه أولاً أن يشحذ أدواته." - كونفوشيوس، "مختارات كونفوشيوس. لو لينجونج"
الصفحة الأمامية > برمجة > كيفية تمرير مؤشرات الوظائف إلى كود C باستخدام Cgo في Go 1.6 والإصدارات الأحدث؟

كيفية تمرير مؤشرات الوظائف إلى كود C باستخدام Cgo في Go 1.6 والإصدارات الأحدث؟

تم النشر بتاريخ 2024-11-09
تصفح:680

How to Pass Function Pointers to C Code Using Cgo in Go 1.6 and Later?

تمرير مؤشر الوظيفة إلى كود C باستخدام Cgo

التغييرات في تمرير مؤشر وظيفة Cgo

في Go 1.6 والإصدارات الأحدث، لدى Cgo قواعد أكثر صرامة للتمرير مؤشرات إلى رمز C. لم يعد مسموحًا بتمرير مؤشر Go الذي يشير إلى ذاكرة Go التي تحتوي على أي مؤشرات Go.

مثال الكود

يوضح كود Go التالي كيفية تمرير مؤشر دالة إلى كود C:

import (
    "fmt"
    "unsafe"
)

/*
   extern void go_callback_int(void* foo, int p1);

   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 := *(*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 = MyCallback

func Example() {
    C.CallMyFunction(unsafe.Pointer(&MyCallbackFunc))
}

func main() {
    Example()
}

الخطأ والحل

عند تشغيل هذا الرمز، ينتج خطأ لأن ذاكرة Go المشار إليها بواسطة MyCallbackFunc تحتوي على مؤشر وظيفة Go (MyCallback).

للعنوان هذا، نحتاج إلى إيجاد طريقة لتمرير مؤشر الوظيفة إلى كود C دون انتهاك القواعد الجديدة.

استخدام معرف بدلاً من المؤشر

تتمثل إحدى الطرق في تخزين مؤشر الوظيفة في بنية بيانات متزامنة وتمرير معرف إلى كود C بدلاً من المؤشر المباشر. بهذه الطريقة، يمكن لرمز C استخدام المعرف للوصول إلى مؤشر الوظيفة من خلال بنية البيانات.

الحزمة مع تمرير مؤشر الوظيفة المستند إلى المعرف

package gocallback

import (
    "fmt"
    "sync"
)

/*
extern void go_callback_int(int foo, int p1);

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)
}
أحدث البرنامج التعليمي أكثر>

تنصل: جميع الموارد المقدمة هي جزئيًا من الإنترنت. إذا كان هناك أي انتهاك لحقوق الطبع والنشر الخاصة بك أو الحقوق والمصالح الأخرى، فيرجى توضيح الأسباب التفصيلية وتقديم دليل على حقوق الطبع والنشر أو الحقوق والمصالح ثم إرسالها إلى البريد الإلكتروني: [email protected]. سوف نتعامل مع الأمر لك في أقرب وقت ممكن.

Copyright© 2022 湘ICP备2022001581号-3