Cgo:第一步教程
一些例子来理解使用 Go C Bindings 的工作流程
什么
在 Go 中,你可以使用 cgo 调用 C 程序和函数。这样,你可以轻松地为提供 C API 的其他应用程序或库创建 C 绑定。
怎么样
所有你需要做的是增加你的围棋程序的开始 import "C"
只包括你的 C 程序后:
//#include <stdio.h>
import "C"
在前面的示例中,你可以在 Go 中使用 stdio
包。
如果你需要使用同一文件夹中的应用程序,则使用与 C 相同的语法(使用 "
而不是 <>
)
//#include "hello.c"
import "C"
重要提示 :不要在
include
和import "C"
语句**之间留下换行符,**否则你将在构建时遇到此类错误:
# command-line-arguments
could not determine kind of name for C.Hello
could not determine kind of name for C.sum
这个例子
在此文件夹中,你可以找到 C 绑定的示例。我们有两个非常简单的 C库叫做 hello.c
:
//hello.c
#include <stdio.h>
void Hello(){
printf("Hello world
");
}
这只是在控制台和 sum.c
中打印 hello world
//sum.c
#include <stdio.h>
int sum(int a, int b) {
return a + b;
}
…需要 2 个参数并返回其总和(不要打印它)。
我们有一个 main.go
程序,它将使用这两个文件。首先我们如前所述导入它们:
//main.go
package main
/*
#include "hello.c"
#include "sum.c"
*/
import "C"
Hello World!
现在我们准备在 Go 应用程序中使用 C 程序了。我们先试试 Hello 程序:
//main.go
package main
/*
#include "hello.c"
#include "sum.c"
*/
import "C"
func main() {
//Call to void function without params
err := Hello()
if err != nil {
log.Fatal(err)
}
}
//Hello is a C binding to the Hello World "C" program. As a Go user you could
//use now the Hello function transparently without knowing that it is calling
//a C function
func Hello() error {
_, err := C.Hello() //We ignore first result as it is a void function
if err != nil {
return errors.New("error calling Hello function: " + err.Error())
}
return nil
}
现在使用 go run main.go
运行 main.go 程序来获取 C 程序的打印:Hello World!
。做得好!
整数总和
让我们通过添加一个对其两个参数求和的函数来使它更复杂一些。
//sum.c
#include <stdio.h>
int sum(int a, int b) {
return a + b;
}
我们将从之前的 Go 应用程序中调用它。
//main.go
package main
/*
#include "hello.c"
#include "sum.c"
*/
import "C"
import (
"errors"
"fmt"
"log"
)
func main() {
//Call to void function without params
err := Hello()
if err != nil {
log.Fatal(err)
}
//Call to int function with two params
res, err := makeSum(5, 4)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Sum of 5 + 4 is %d
", res)
}
//Hello is a C binding to the Hello World "C" program. As a Go user you could
//use now the Hello function transparently without knowing that is calling a C
//function
func Hello() error {
_, err := C.Hello() //We ignore first result as it is a void function
if err != nil {
return errors.New("error calling Hello function: " + err.Error())
}
return nil
}
//makeSum also is a C binding to make a sum. As before it returns a result and
//an error. Look that we had to pass the Int values to C.int values before using
//the function and cast the result back to a Go int value
func makeSum(a, b int) (int, error) {
//Convert Go ints to C ints
aC := C.int(a)
bC := C.int(b)
sum, err := C.sum(aC, bC)
if err != nil {
return 0, errors.New("error calling Sum function: " + err.Error())
}
//Convert C.int result to Go int
res := int(sum)
return res, nil
}
看看 makeSum
功能。它通过使用 C.int
函数接收两个需要转换为 C int
的 int
参数。此外,呼叫的返回将给我们一个 C int
并在出现问题时出错。我们需要使用 int()
将 Go 响应转换为 Go 的 int。
尝试使用 go run main.go
运行我们的应用程序
$ go run main.go
Hello world!
Sum of 5 + 4 is 9
生成二进制文件
如果你尝试 go build,你可能会遇到多个定义错误。
$ go build
# github.com/sayden/c-bindings
/tmp/go-build329491076/github.com/sayden/c-bindings/_obj/hello.o: In function `Hello':
../../go/src/github.com/sayden/c-bindings/hello.c:5: multiple definition of `Hello'
/tmp/go-build329491076/github.com/sayden/c-bindings/_obj/main.cgo2.o:/home/mariocaster/go/src/github.com/sayden/c-bindings/hello.c:5: first defined here
/tmp/go-build329491076/github.com/sayden/c-bindings/_obj/sum.o: In function `sum':
../../go/src/github.com/sayden/c-bindings/sum.c:5: multiple definition of `sum`
/tmp/go-build329491076/github.com/sayden/c-bindings/_obj/main.cgo2.o:/home/mariocaster/go/src/github.com/sayden/c-bindings/sum.c:5: first defined here
collect2: error: ld returned 1 exit status
诀窍是在使用 go build
时直接引用主文件:
$ go build main.go
$ ./main
Hello world!
Sum of 5 + 4 is 9
请记住,你可以使用
-o
flaggo build -o my_c_binding main.go
为二进制文件提供名称
我希望你喜欢这个教程。