」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > 如何在 Go 1.6 及更高版本中使用 Cgo 將函數指標傳遞給 C 程式碼?

如何在 Go 1.6 及更高版本中使用 Cgo 將函數指標傳遞給 C 程式碼?

發佈於2024-11-09
瀏覽:248

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

使用Cgo 將函數指標傳遞給C 程式碼

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

錯誤及解決方案

運行這段程式碼時,會產生錯誤,因為MyCallbackFunc指向的Go記憶體中包含一個Go函數指標(MyCallback)。

要地址為此,我們需要找到一種方法將函數指標傳遞給 C 程式碼而不違反新規則。

使用 ID 而不是指標

一種方法是將函數指標儲存在同步資料結構中,並將 ID 傳遞給 C 程式碼而不是直接指標。這樣,C 程式碼就可以使用 ID 透過資料結構存取函數指標。

基於 ID 的函數指標傳遞的程式碼

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)
}
最新教學 更多>
  • Nginx 在 https 埠上強制 http 轉為 https
    Nginx 在 https 埠上強制 http 轉為 https
    範例腳本 nginx : server { listen 443 default ssl; listen [::]:443 ssl; root /var/www/html/api_mobile/public; include snip...
    程式設計 發佈於2024-11-09
  • 如何使用 Google Maps API v2 取得行車路線?
    如何使用 Google Maps API v2 取得行車路線?
    使用Google Maps API v2 獲取行車路線您在問題中提到的請求使用了Google Maps API 的addPolyline 方法在兩點之間畫一條直線。此方法旨在在地圖上顯示簡單的線條,而不是用於檢索行車路線。 要取得兩個位置之間的詳細行車說明,您應該將 Google Maps Dire...
    程式設計 發佈於2024-11-09
  • 使用 React Query 建立 Feed 頁面
    使用 React Query 建立 Feed 頁面
    目标 在本文中,我们将探索如何使用 React Query 构建提要页面! 这是我们将要创建的内容: 本文不会涵盖构建应用程序所涉及的每个步骤和细节。 相反,我们将重点关注关键功能,特别是“无限滚动”和“滚动到顶部”功能。 如果您有兴趣咨询整个实现,您可以在此 GitHub 存...
    程式設計 發佈於2024-11-09
  • `useCallback` 與 `useMemo` 掛鉤
    `useCallback` 與 `useMemo` 掛鉤
    提升 React 效能:useCallback 與 useMemo Hooks React 的 useCallback 和 useMemo 掛鉤對於優化應用程式的效能至關重要。了解何時以及如何使用它們可以使您避免不必要的重新渲染並確保您的應用程式順利運行。在本文中,我們將深入研究有...
    程式設計 發佈於2024-11-09
  • PHP 中的多重繼承
    PHP 中的多重繼承
    繼承:繼承是物件導向程式設計(OOP)中的一個基本概念,它允許類別從其他類別繼承屬性和行為。它是一種基於現有類別創建新類別、促進程式碼重用以及在類別之間建立層次關係的機制。 繼承是基於「父子」或「超類別-子類別」關係的概念。另一個類別繼承自的類別稱為超類別或基底類,而從超類別繼承的類別稱為子類別或衍...
    程式設計 發佈於2024-11-09
  • jQuery 如何簡化 JSON 資料到 HTML 表的轉換?
    jQuery 如何簡化 JSON 資料到 HTML 表的轉換?
    jQuery 的JSON 到HTML 表格轉換的簡化方法將JSON 陣列轉換為HTML 表格可能是一項繁瑣的任務,但jQuery 簡化了這個過程要從JSON 陣列產生表,請使用getJSON() 函數檢索資料:$.getJSON(url , function(data) {接下來,建立表格主體:va...
    程式設計 發佈於2024-11-09
  • 如何從 Node.js 中的大型 Firebase 資料集中有效率地檢索隨機乘積?
    如何從 Node.js 中的大型 Firebase 資料集中有效率地檢索隨機乘積?
    如何在 Node Firebase 中檢索唯一的隨機乘積? Firebase 提供靈活的資料結構,讓您以分層方式儲存資料。在某些情況下,您可能擁有大量記錄,但只需要一筆唯一且隨機的記錄。本文將引導您透過兩種方法在 Node Firebase 中實現此目的。 經典方法:下載所有記錄假設您的資料庫結構類...
    程式設計 發佈於2024-11-09
  • PHP 中的 session_unset() 和 session_destroy() 有什麼不同?
    PHP 中的 session_unset() 和 session_destroy() 有什麼不同?
    深入探討PHP 中session_unset() 和session_destroy() 之間的差異使用PHP 會話時,開發人員通常必須在函數session_unset() 和session_destroy()。儘管聽起來相似,但這些函數表現出顯著的差異。 功能差異雖然這兩個函數都會影響會話變量,但它...
    程式設計 發佈於2024-11-09
  • 如何在 JavaScript 中組合陣列並同時儲存唯一元素?
    如何在 JavaScript 中組合陣列並同時儲存唯一元素?
    在JavaScript 中將數組與唯一元素組合要基於唯一項合併數組,您可以利用以下技術:var newCells = []; for (var i = 0; i < totalCells.length; i ) { var lineNumber = totalCells[i].lin...
    程式設計 發佈於2024-11-09
  • 將日期物件轉換為時間戳記時,一元加運算子有何作用?
    將日期物件轉換為時間戳記時,一元加運算子有何作用?
    Unary Plus:將日期物件轉換為毫秒時間戳在JavaScript 中,您可能會遇到類似以下內容的程式碼:function fn() { return new Date; }此表達式傳回表示當前時間的時間戳,而不是完整的 Date 物件。然而,加號 ( ) 的作用並不是立即顯而易見。 答案...
    程式設計 發佈於2024-11-09
  • 如何消除 Mac 版 Chrome 中不需要的「過度滾動」?
    如何消除 Mac 版 Chrome 中不需要的「過度滾動」?
    克服網頁中的「過度滾動」在Mac 版Chrome 中,「過度滾動」是一種不良效果,它允許用戶將頁面拖到其正常查看區域之外,如所提供的影像所示。若要解決此問題並改善使用者體驗,請考慮以下兩種方法:方法一:限制過度捲動如果要完全停用過度捲動,請使用下列CSS 程式碼: html { overfl...
    程式設計 發佈於2024-11-09
  • ## 為什麼 JQuery 的 `load()` 函數在不同瀏覽器中表現不同?
    ## 為什麼 JQuery 的 `load()` 函數在不同瀏覽器中表現不同?
    Jquery load() 跨瀏覽器的不一致Jquery load() 跨瀏覽器的不一致在嘗試深入研究JQuery 和AJAX 時,開發人員可能會遇到一個特殊的問題,其中load( ) 函數在不同瀏覽器中表現出不一致的行為。具體來說,在提供的程式碼片段中,load()函數用於將list1.html的...
    程式設計 發佈於2024-11-09
  • 為什麼我在 Go 中收到「語法錯誤:Else 之前出現意外的分號」?
    為什麼我在 Go 中收到「語法錯誤:Else 之前出現意外的分號」?
    Go 中 Else 之前意外的分號:詳細解釋你的 Go 碼在第 21 行遇到異常錯誤:「syntax error:unexpected其他之前的分號或換行符。 這裡的核心問題源自於Go的自動分號插入規則。通常,Go 中分號是可選的;但是,編譯器會自動將它們插入到某些行的末尾以保持語法完整性。其中一個...
    程式設計 發佈於2024-11-09
  • 如何防止 Apache 快取 CSS 檔案並確保顯示最新版本?
    如何防止 Apache 快取 CSS 檔案並確保顯示最新版本?
    使用Apache 防止伺服器端CSS 檔案快取開發網站時,確保訪客存取最新版本至關重要用於防止快取問題的CSS 文件。本文解決了 Apache 是否快取資源的問題,並提供了防止其這樣做的解決方案,特別是遇到儘管重新載入頁面但 CSS 變更未反映在瀏覽器中的場景時。 是Apache 真的會快取資源嗎?...
    程式設計 發佈於2024-11-09
  • 您應該使用哪種 MySQL 整數資料類型?
    您應該使用哪種 MySQL 整數資料類型?
    了解MySQL 整數資料類型之間的差異MySQL 提供了一系列整數資料類型,它們的儲存需求和值範圍各不相同。這些類型包括tinyint、smallint、mediumint、bigint 和int。了解它們之間的差異對於為您的特定資料需求選擇適當的資料類型至關重要。 資料大小和範圍注意​​事項這些資...
    程式設計 發佈於2024-11-09

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3