
本文详细介绍了如何在 Go 语言中调用 C 函数,特别是如何处理 C 函数回调 Go 函数的情况。通过具体的代码示例,展示了如何使用 cgo 工具以及 //export 指令,实现 Go 代码与 C 代码的互操作,并提供了一种通用的解决方案,允许用户自定义回调函数,从而在 C 代码执行过程中将进度信息传递回 Go 程序。
Go 语言提供了 cgo 工具,允许 Go 代码调用 C 代码,这在需要利用现有 C 库或进行底层系统编程时非常有用。本文将重点介绍如何从 C 代码中回调 Go 函数,并提供详细的示例代码和步骤说明。
首先,让我们回顾一下 Go 如何调用 C 函数。这通常涉及到以下步骤:
例如:
package main
// #include <stdio.h>
import "C"
func main() {
C.puts(C.CString("Hello, C world!"))
}从 C 代码回调 Go 函数稍微复杂一些,但 cgo 提供了机制来实现这一目标。关键在于使用 //export 指令标记 Go 函数,并使用 extern 关键字在 C 代码中声明该函数。
示例 1:简单的加法回调
以下是一个简单的示例,演示了如何从 C 代码回调一个 Go 函数,该函数执行加法运算:
package main
// extern int goCallbackHandler(int, int);
//
// static int doAdd(int a, int b) {
// return goCallbackHandler(a, b);
// }
import "C"
import "fmt"
//export goCallbackHandler
func goCallbackHandler(a, b C.int) C.int {
fmt.Printf("goCallbackHandler called with a=%d, b=%d\n", a, b)
return a + b
}
// MyAdd is a Go function that calls a C function which in turn calls back to Go.
func MyAdd(a, b int) int {
return int(C.doAdd(C.int(a), C.int(b)))
}
func main() {
result := MyAdd(5, 3)
fmt.Printf("Result of MyAdd(5, 3): %d\n", result)
}代码解释:
编译和运行:
示例 2:带用户自定义数据的回调
更复杂的情况是,我们需要将用户自定义的数据传递给回调函数。这可以通过将数据打包到 void* 指针中来实现。
package main
// #include <stdio.h>
// #include <stdlib.h>
//
// typedef void (*progress_callback)(unsigned long long current, unsigned long long total, void* userdata);
//
// extern void goProgressCB(unsigned long long current, unsigned long long total, void* userdata);
//
// static void simulate_progress(progress_callback cb, void* userdata) {
// unsigned long long total = 100;
// for (unsigned long long i = 0; i <= total; i++) {
// cb(i, total, userdata);
// }
// }
import "C"
import (
"fmt"
"unsafe"
)
// ProgressHandler defines the signature of our user's progress handler
type ProgressHandler func(current, total uint64, userdata interface{})
// progressRequest is an internal type which will pack the users callback function and userdata.
type progressRequest struct {
f ProgressHandler // The user's function pointer
d interface{} // The user's userdata.
}
//export goProgressCB
func goProgressCB(current, total C.ulonglong, userdata unsafe.Pointer) {
req := (*progressRequest)(userdata)
req.f(uint64(current), uint64(total), req.d)
}
// SimulateProgress simulates a C function that reports progress using a callback.
func SimulateProgress(pf ProgressHandler, userdata interface{}) {
req := &progressRequest{pf, userdata}
C.simulate_progress(C.progress_callback(C.goProgressCB), unsafe.Pointer(req))
}
func main() {
myProgress := func(current, total uint64, userdata interface{}) {
fmt.Printf("Progress: %d/%d, Userdata: %v\n", current, total, userdata)
}
SimulateProgress(myProgress, "Hello from Go!")
}代码解释:
注意事项:
总结:
通过 cgo,我们可以方便地在 Go 代码中调用 C 代码,并且可以从 C 代码回调 Go 函数。这使得我们可以利用现有的 C 库,并使用 Go 语言的优势来构建高性能的应用程序。 理解 //export 的用法以及数据类型转换是关键。 此外,需要特别注意内存管理,避免内存泄漏。
以上就是在 Go 中调用 C 函数的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号