”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 如何在 Go 1.6 及更高版本中使用 Cgo 将函数指针传递给 C 代码?

如何在 Go 1.6 及更高版本中使用 Cgo 将函数指针传递给 C 代码?

发布于2024-11-09
浏览:132

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)
}
最新教程 更多>
  • 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].li...
    编程 发布于2024-11-09
  • 将日期对象转换为时间戳时,一元加运算符有何作用?
    将日期对象转换为时间戳时,一元加运算符有何作用?
    Unary Plus:将日期对象转换为毫秒时间戳在 JavaScript 中,您可能会遇到类似于以下内容的代码:function fn() { return new Date; }此表达式返回表示当前时间的时间戳,而不是完整的 Date 对象。然而,加号 ( ) 的作用并不是立即显而易见。答案...
    编程 发布于2024-11-09
  • 如何消除 Mac 版 Chrome 中不需要的“过度滚动”?
    如何消除 Mac 版 Chrome 中不需要的“过度滚动”?
    克服网页中的“过度滚动”在 Mac 版 Chrome 中,“过度滚动”是一种不良效果,它允许用户将页面拖到其正常查看区域之外,如所提供的图像所示。要解决此问题并改善用户体验,请考虑以下两种方法:方法一:限制过度滚动如果要完全禁用过度滚动,请使用以下 CSS 代码:html { overflo...
    编程 发布于2024-11-09
  • ## 为什么 JQuery 的 `load()` 函数在不同浏览器中表现不同?
    ## 为什么 JQuery 的 `load()` 函数在不同浏览器中表现不同?
    Jquery load() 跨浏览器的不一致在尝试深入研究 JQuery 和 AJAX 时,开发人员可能会遇到一个特殊的问题,其中 load( ) 函数在不同浏览器中表现出不一致的行为。具体来说,在提供的代码片段中,load()函数用于将list1.html的内容附加到index.html上id为“...
    编程 发布于2024-11-09
  • 为什么我在 Go 中收到“语法错误:Else 之前出现意外的分号”?
    为什么我在 Go 中收到“语法错误:Else 之前出现意外的分号”?
    Go 中 Else 之前意外的分号:详细解释你的 Go 代码在第 21 行遇到异常错误:“syntax error:unexpected其他之前的分号或换行符。”尽管你这么说,但仔细检查发现,这一行的“else”语句之前确实有一个分号(;)。这里的核心问题源于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
  • 为什么我在 JavaScript 中的输入值为空?
    为什么我在 JavaScript 中的输入值为空?
    输入值和变量存储:为什么会陷入空困境?当尝试使用 JavaScript 从输入字段检索值时,开发人员经常遇到如果数据存储在变量中,则为空值。这个令人费解的问题可能源于 Web 开发的异步特性以及浏览器执行代码的方式。在 JavaScript 中,执行脚本时会检索输入字段的初始值。如果稍后在 HTML...
    编程 发布于2024-11-09
  • 如何使用 RequestAnimationFrame 来稳定动画的帧速率 (FPS)?
    如何使用 RequestAnimationFrame 来稳定动画的帧速率 (FPS)?
    RequestAnimationFrame Fps 稳定RequestAnimationFrame (rAF) 已在动画中变得流行,可提供流畅且高效的执行。然而,控制帧速率 (FPS) 以确保一致性可能具有挑战性。将 rAF 限制为特定 FPS要将 rAF 限制为特定 FPS,您可以自上一帧执行以来...
    编程 发布于2024-11-09
  • 适合初学者的关键 Python 术语
    适合初学者的关键 Python 术语
    您是否曾经在与程序员交谈时,因不熟悉的行话而感到茫然?或者,也许您是 Python 编程的初学者,并且遇到了某些您不完全理解的术语。学习Python中使用的常用术语不仅可以帮助你更专业地解释你的代码,还可以让你更轻松地跟上讨论。本文通过简单的解释、用例和示例探讨了基本的 Python 术语,以帮助您...
    编程 发布于2024-11-09
  • 使用 Puppeteer 生成 PDF 之前如何确保页面完成?
    使用 Puppeteer 生成 PDF 之前如何确保页面完成?
    使用 Puppeteer 生成 PDF:等待页面完成使用 Puppeteer 从网页创建 PDF 时,等待页面完全加载以确保完整性至关重要以及生成文档的准确性。让我们深入研究如何在不诉诸手动延迟的情况下实现此目的。page.waitForNavigation() 方法提供了一种可靠的方法来等待页面导...
    编程 发布于2024-11-09
  • 为什么 Angular 1.6 将 URL 哈希前缀从 # 更改为 #!?
    为什么 Angular 1.6 将 URL 哈希前缀从 # 更改为 #!?
    URL 哈希前缀从 # 更改为 #!在 Angular 1.6 中自从 AngularJS 1.6 的最新更新以来,用户已经注意到 URL 格式的变化。 AngularJS 现在不再使用以前的“#/”哈希前缀,而是使用“#!/”。更改的原因是什么?更改归因于AngularJS 1.6 中引入的新哈希...
    编程 发布于2024-11-09
  • 如何在 Python 中将整数转换为字节字符串并返回?
    如何在 Python 中将整数转换为字节字符串并返回?
    使用“bytes(n)”创建字节字符串Python 3 中的“bytes(n)”函数不会将整数转换为其二进制表示形式,而是创建长度为 n 的字节字符串,并用空字节 (b'\x00') 填充。此行为源于 Python 3.2,其中引入了“to_bytes()”方法作为将整数编码为字节的...
    编程 发布于2024-11-09
  • Button的“命令”参数函数什么时候执行?
    Button的“命令”参数函数什么时候执行?
    声明时按钮的“command”参数执行:解开谜团在Python tkinter中,Button小部件的“command”参数旨在指定一个函数当按下按钮时执行。然而,初学者的一个常见误解是,即使在声明按钮时,与“command”相关的函数也会被执行。要理解这种行为,我们需要深入研究Python如何处理...
    编程 发布于2024-11-09

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3