我正在尝试创建一个用Go语言编写的静态对象,以与C程序(例如内核模块等)进行接口。
我已经找到了有关从Go调用C函数的文档,但是关于如何走另一条路却找不到很多。我发现这是可能的,但很复杂。
这是我发现的:
有关C和Go之间的回调的博客文章
CGO文档
Golang邮件列表帖子
有任何人对此有经验吗?简而言之,我正在尝试创建一个完全用Go编写的PAM模块。
您可以从C调用Go代码。但这是一个令人困惑的主张。
您链接到的博客文章中概述了该过程。但是我可以看到这不是很有帮助。这是一个简短的片段,没有任何不必要的内容。它应该使事情更加清晰。
package foo
// extern int goCallbackHandler(int, int);
//
// static int doAdd(int a, int b) {
// return goCallbackHandler(a, b);
// }
import "C"
//export goCallbackHandler
func goCallbackHandler(a, b C.int) C.int {
return a + b
}
// This is the public function, callable from outside this package.
// It forwards the parameters to C.doAdd(), which in turn forwards
// them back to goCallbackHandler(). This one performs the addition
// and yields the result.
func MyAdd(a, b int) int {
return int( C.doAdd( C.int(a), C.int(b)) )
}
一切调用的顺序如下:
foo.MyAdd(a, b) ->
C.doAdd(a, b) ->
C.goCallbackHandler(a, b) ->
foo.goCallbackHandler(a, b)
这里要记住的关键是,回调函数必须//export
在Go侧和extern
C侧都标记有注释。这意味着您要使用的任何回调都必须在包中定义。
为了允许您的包用户提供自定义回调函数,我们使用与上述方法完全相同的方法,但是我们提供了用户的自定义处理程序(只是常规的Go函数)作为传递给C的参数侧为void*
。然后,它由我们的包中的回调处理程序接收并调用。
让我们使用我目前正在使用的更高级的示例。在这种情况下,我们有一个C函数来执行一项繁重的任务:它从USB设备读取文件列表。这可能需要一段时间,因此我们希望通知我们的应用程序进度。我们可以通过传入我们在程序中定义的函数指针来做到这一点。每当调用它时,它仅向用户显示一些进度信息。由于它具有众所周知的签名,因此我们可以为其分配自己的类型:
type ProgressHandler func(current, total uint64, userdata interface{}) int
该处理程序获取一些进度信息(当前接收的文件数和文件总数)以及interface {}值,该值可以容纳用户需要保存的任何内容。
现在,我们需要编写C和Go管道,以允许我们使用此处理程序。幸运的是,我希望从库中调用的C函数允许我们传递type的userdata结构void*
。这意味着它可以容纳我们想要容纳的任何东西,不问任何问题,我们将其按原样带回到Go世界。为了使所有这些工作正常进行,我们没有直接从Go中调用库函数,而是为其创建了一个C包装器,我们将其命名为goGetFiles()
。实际上,此包装器将我们的Go回调与userdata对象一起提供给C库。
package foo
// #include <somelib.h>
// extern int goProgressCB(uint64_t current, uint64_t total, void* userdata);
//
// static int goGetFiles(some_t* handle, void* userdata) {
// return somelib_get_files(handle, goProgressCB, userdata);
// }
import "C"
import "unsafe"
请注意,该goGetFiles()
函数不将回调的任何函数指针作为参数。相反,我们的用户提供的回调包含在一个自定义结构中,该结构既包含该处理程序,又包含用户自己的userdata值。我们将其goGetFiles()
作为userdata参数传递。
// This defines the signature of our user's progress handler,
type ProgressHandler func(current, total uint64, userdata interface{}) int
// This is an internal type which will pack the users callback function and userdata.
// It is an instance of this type that we will actually be sending to the C code.
type progressRequest struct {
f ProgressHandler // The user's function pointer
d interface{} // The user's userdata.
}
//export goProgressCB
func goProgressCB(current, total C.uint64_t, userdata unsafe.Pointer) C.int {
// This is the function called from the C world by our expensive
// C.somelib_get_files() function. The userdata value contains an instance
// of *progressRequest, We unpack it and use it's values to call the
// actual function that our user supplied.
req := (*progressRequest)(userdata)
// Call req.f with our parameters and the user's own userdata value.
return C.int( req.f( uint64(current), uint64(total), req.d ) )
}
// This is our public function, which is called by the user and
// takes a handle to something our C lib needs, a function pointer
// and optionally some user defined data structure. Whatever it may be.
func GetFiles(h *Handle, pf ProgressFunc, userdata interface{}) int {
// Instead of calling the external C library directly, we call our C wrapper.
// We pass it the handle and an instance of progressRequest.
req := unsafe.Pointer(&progressequest{ pf, userdata })
return int(C.goGetFiles( (*C.some_t)(h), req ))
}
这就是我们的C绑定。用户的代码现在非常简单:
package main
import (
"foo"
"fmt"
)
func main() {
handle := SomeInitStuff()
// We call GetFiles. Pass it our progress handler and some
// arbitrary userdata (could just as well be nil).
ret := foo.GetFiles( handle, myProgress, "Callbacks rock!" )
....
}
// This is our progress handler. Do something useful like display.
// progress percentage.
func myProgress(current, total uint64, userdata interface{}) int {
fc := float64(current)
ft := float64(total) * 0.01
// print how far along we are.
// eg: 500 / 1000 (50.00%)
// For good measure, prefix it with our userdata value, which
// we supplied as "Callbacks rock!".
fmt.Printf("%s: %d / %d (%3.2f%%)\n", userdata.(string), current, total, fc / ft)
return 0
}
这一切看起来都比实际复杂得多。与前面的示例相比,呼叫顺序没有改变,但是在链的末尾我们得到了两个额外的呼叫:
顺序如下:
foo.GetFiles(....) ->
C.goGetFiles(...) ->
C.somelib_get_files(..) ->
C.goProgressCB(...) ->
foo.goProgressCB(...) ->
main.myProgress(...)
问题内容: 您好Go Lang和C#专家, 美好的一天。我想问你们是否有人尝试过Go程序调用C#DLL函数(类库类型)? 我进行了一些初步研究,并看到了以下文章: 但是这些都是从C Win32实现中创建的DLL。我尝试搜索加载到Go程序中的C#DLL,所有这些都会告诉您在Go程序上调用它之前,您需要具有C ++ / C(Win32)包装器。 另外,上面的链接将告诉您Go认为我认为是“ C”声明(类
问题内容: 我正在尝试从C ++实现调用Python函数。我以为可以通过函数指针来实现,但是似乎不可能。我一直在使用以完成此任务。 假设在Python中定义了一个函数: 现在,我需要将此函数传递给C ,以便可以从那里调用它。如何在C 端编写代码以实现此目的? 问题答案: 如果可以使用任何名称: 将其传递给需要一个的函数。 如果它在具有相同名称的单个已知名称空间中: 已定义,因此您可以像调用任何函数
问题内容: 我有一个C函数,我想从C 调用。我无法使用“ ”这样的方法,因为C函数无法使用g 进行编译。但是使用gcc可以很好地编译。有什么想法如何从C ++调用函数吗? 问题答案: 像这样编译C代码: 然后是这样的C ++代码: 然后使用C ++链接器将它们链接在一起: 当您包含C函数的声明时,还必须告诉C ++编译器C头即将到来。因此开始于: 应该包含以下内容: (在此示例中,我使用了gcc,
问题内容: 我可以在下面从C中调用不带参数的Go函数。通过编译并打印 main.go 文件1.c 现在,我想将字符串/字符数组从C传递给GoFunction。 根据cgo文档中的 “对Go的C引用”,这是可能的,因此我向GoFunction添加了一个字符串参数,并将char数组传递给GoFunction: main.go 文件1.c 当我收到此错误: 其他参考:( 信誉不足,无法发布3个链接)根据
在 Go 语言开篇中我们已经知道,Go 语言与 C 语言之间有着千丝万缕的关系,甚至被称之为 21 世纪的C语言。 所以在 Go 与 C 语言互操作方面,Go 更是提供了强大的支持。尤其是在 Go 中使用 C,你甚至可以直接在 Go 源文件中编写 C 代码,这是其他语言所无法望其项背的。 格式: 在 import "C" 之前通过单行注释或者通过多行注释编写C语言代码 在 import "C" 之
cgo不仅仅支持从Go调用C,它还同样支持从C中调用Go的函数,虽然这种情况相对前者较少使用。 //export GoF func GoF(arg1, arg2 int, arg3 string) int64 { } 使用export标记可以将Go函数导出提供给C调用: extern int64 GoF(int arg1, int arg2, GoString arg3); 下面让我们看看它是