4b85951ce3833bcded63fb5356bce6e3
CGO简明教程

Hello World

package main

// #include <stdlib.h>
import "C"

import (
    "fmt"
)

func main() {
    fmt.Println(int(C.random()))
}

当然这并不是Hello World。我们不首先输出Hello World是有原因的,接下来就会讲到。不过首先我们分析一下现在这个程序。首先从结构上来看可以知道这就是一个普通的Go程序,第一行 package main 声明这个代码是在main包里。然后下面有 func main 是程序的入口。

// #inlcude <stdlib.h>
import "C"

这三行是Go调C才这样的,import "C" 是为了可以在Go程序里直接使用C里的一些函数,例如main中 C.random(),而 import "C" 上边的注释叫做preamble,注意必须和 import "C"紧紧挨着中间不能有空格。注释的风格可以是 // #include... 也可以是 /*#include ...*/ 这样的。此外可以在 preamble 中加入 // #cgo 开头的注释,用于指示编译和链接中发生的一些事情,例如链接哪个动态链接库等。

接下来我们看看Hello World。

首先我们需要三个文件,helloworld.h:

#ifndef __helloworld
#define __helloworld

void Printf(char *s);

#endif

helloworld.c:

#include <stdio.h>

void Printf(char *s) {
    printf("%s", s);
}

main.go:

package main

// #include "helloworld.h"
import "C"

func main() {
    C.Printf("hello world")
}

为啥不直接 C.printf 输出呢,因为在wiki中提到cgo目前暂时还不支持变长参数的C函数,所以要我们自己包装一下。编译:

$ go build
./main.go:7: cannot use "hello world" (type string) as type *_Ctype_char in argument to _Cfunc_Printf

原因是C和Go的字符串不是通用的,我们要把Go的字符串转成C的字符串,但是因为不是在编译的这个过程申请内存,而是在堆里申请内存存储字符串,而Go的垃圾回收是管不到C申请的内存,所以我们需要自行销毁对应的内存。

```go
package main

top Created with Sketch.