From 4cfa4a2e95f00350f8c6231fca98f1b1e152b418 Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 20 Apr 2013 22:19:12 -0400 Subject: [PATCH] 03.9.md --- README.md | 2 +- eBook/03.9.md | 75 ++++++++++++++++++++++++ eBook/examples/chapter_3/CandGo/Makefile | 7 +++ eBook/examples/chapter_3/CandGo/c1.go | 13 ++++ eBook/examples/chapter_3/CandGo/c2.go | 13 ++++ eBook/examples/chapter_3/Makefile | 7 +++ eBook/examples/chapter_3/gocomp | 9 +++ eBook/examples/chapter_3/gocomp.bat | 2 + eBook/examples/chapter_3/run.cmd | 9 +++ 9 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 eBook/examples/chapter_3/CandGo/Makefile create mode 100644 eBook/examples/chapter_3/CandGo/c1.go create mode 100644 eBook/examples/chapter_3/CandGo/c2.go create mode 100644 eBook/examples/chapter_3/Makefile create mode 100644 eBook/examples/chapter_3/gocomp create mode 100644 eBook/examples/chapter_3/gocomp.bat create mode 100644 eBook/examples/chapter_3/run.cmd diff --git a/README.md b/README.md index 7a22042..4bb9481 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ 该翻译版本已获得原作者(Ivo Balbaert)本人授权,并表示支持开源事业的发展! ##翻译进度 -3.8 [Go 性能说明](eBook/03.8.md) +3.9 [与其它语言进行交互](eBook/03.9.md) ##支持本书 如果你喜欢本书《Go入门指南》,你可以参与到本书的翻译或纠正工作中来,具体请联系译者,一同完善本书并帮助壮大 Go 语言在国内的学习群体,给大家提供更好的学习资源。 diff --git a/eBook/03.9.md b/eBook/03.9.md index ecccd8c..8580923 100644 --- a/eBook/03.9.md +++ b/eBook/03.9.md @@ -14,7 +14,82 @@ #3.9 与其它语言进行交互 #3.9.1 与 C 进行交互 +工具 cgo 提供了对 FFI(外部函数接口)的支持,能够使用 Go 代码安全地调用 C 语言库,你可以访问 cgo 文档主页:[http://golang.org/cmd/cgo](http://golang.org/cmd/cgo)。cgo 会替代 Go 编译器来产生可以组合在同一个包中的 Go 和 C 代码。在实际开发中一般使用 cgo 创建单独的 C 代码包。 +如果你想要在你的 Go 程序中使用 cgo,则必须在单独的一行使用 `import "C"` 来导入,一般来说你可能还需要 `import "unsafe"`。 + +然后,你可以在 `import "C"` 之前使用注释(单行或多行注释均可)的形式导入 C 语言库(甚至有效的 C 语言代码),它们之间没有空行,例如: + + // #include + // #include + import “C” + +名称 "C" 并不属于标准库的一部分,这只是 cgo 集成的一个特殊名称用于引用 C 的命名空间。在这个命名空间里所包含的 C 类型都可以被使用,例如 C.uint、C.long 等等,还有 libc 中的函数 C.random() 等也可以被调用。 + +当你想要使用某个类型作为 C 中函数的参数时,必须将其转换为 C 中的类型,反之亦然,例如: + + var i int + C.uint(i) // 从 Go 中的 int 转换为 C 中的无符号 int + int(C.random()) // 从 C 中 random() 函数返回的 long 转换为 Go 中的 int + +下面的 2 个 Go 函数 Random() 和 Seed() 分别调用了 C 中的 C.random() 和 C.srandom()。 + +Example 3.2 [c1.go](examples/chapter_3/CandGo/c1.go) + + package rand + // #include + import “C” + func Random() int { + return int(C.random()) + } + func Seed(i int) { + C.srandom(C.uint(i)) + } + +C 当中并没有明确的字符串类型,如果你想要将一个 string 类型的变量从 Go 转换到 C,可以使用 `C.CString(s)`;同样,可以使用 `C.GoString(cs)` 从 C 转换到 Go 中的 string 类型。 + +Go 的内存管理机制无法管理通过 C 代码分配的内存。 + +开发人员需要通过手动调用 `C.free` 来释放变量的内存: + + defer C.free(unsafe.Pointer(Cvariable)) + +这一行最好紧跟在使用 C 代码创建某个变量之后,这样就不会忘记释放内存了。下面的代码展示了如何使用 cgo 创建变量、使用并释放其内存: + +Example 3.3 [c2.go](examples/chapter_3/CandGo/c2.go) + + package print + // #include + // #include + import “C” + import “unsafe” + func Print(s string) { + cs := C.CString(s) + defer C.free(unsafe.Pointer(cs)) + C.fputs(cs, (*C.FILE)(C.stdout)) + } + +**构建 cgo 包** + +你可以在使用将会在第 9.5 节讲到的 Makefile 文件(因为我们使用了一个独立的包),除了使用变量 GOFILES 之外,还需要使用变量 CGOFILES 来列出需要使用 cgo 编译的文件列表。例如,Example 3.2 中的代码就可以使用包含以下内容的 Makefile 文件来编译,你可以使用 gomake 或 make: + + include $(GOROOT)/src/Make.inc + TARG=rand + CGOFILES=\ + c1.go\ + include $(GOROOT)/src/Make.pkg + +#3.9.2 与 C++ 进行交互 +SWIG(简化封装器和接口生成器)支持在 Linux 系统下使用 Go 代码调用 C 或者 C++ 代码。这里有一些使用 SWIG 的注意事项: + +- 编写需要封装的库的 SWIG 接口。 +- SWIG 会产生 C 的存根函数。 +- 这些库可以使用 cgo 来调用。 +- 相关的 Go 文件也可以被自动生成。 + +这类接口支持方法重载、多重继承以及使用 Go 代码实现 C++ 的抽象类。 + +目前使用 SWIG 存在的一个问题是它无法支持所有的 C++ 库,比如说它就无法解析 TObject.h。 ##链接 - [目录](directory.md) diff --git a/eBook/examples/chapter_3/CandGo/Makefile b/eBook/examples/chapter_3/CandGo/Makefile new file mode 100644 index 0000000..a05adee --- /dev/null +++ b/eBook/examples/chapter_3/CandGo/Makefile @@ -0,0 +1,7 @@ +include $(GOROOT)/src/Make.inc + +TARG=rand +CGOFILES=\ + c1.go\ + +include $(GOROOT)/src/Make.pkg \ No newline at end of file diff --git a/eBook/examples/chapter_3/CandGo/c1.go b/eBook/examples/chapter_3/CandGo/c1.go new file mode 100644 index 0000000..c072630 --- /dev/null +++ b/eBook/examples/chapter_3/CandGo/c1.go @@ -0,0 +1,13 @@ +// c1.go +package rand + +// #include +import "C" + +func Random() int { + return int(C.random()) +} + +func Seed(i int) { + C.srandom(C.uint(i)) +} diff --git a/eBook/examples/chapter_3/CandGo/c2.go b/eBook/examples/chapter_3/CandGo/c2.go new file mode 100644 index 0000000..f734763 --- /dev/null +++ b/eBook/examples/chapter_3/CandGo/c2.go @@ -0,0 +1,13 @@ +// c2.go +package print + +// #include +// #include +import "C" +import "unsafe" + +func Print(s string) { + cs := C.CString(s) + defer C.free(unsafe.Pointer(cs)) + C.fputs(cs, (*C.FILE)(C.stdout)) +} diff --git a/eBook/examples/chapter_3/Makefile b/eBook/examples/chapter_3/Makefile new file mode 100644 index 0000000..0026f79 --- /dev/null +++ b/eBook/examples/chapter_3/Makefile @@ -0,0 +1,7 @@ + include $(GOROOT)/src/Make.inc +TARG=test +GOFILES=\ + test1.go\ +test2.go\ + +include $(GOROOT)/src/Make.cmd diff --git a/eBook/examples/chapter_3/gocomp b/eBook/examples/chapter_3/gocomp new file mode 100644 index 0000000..a7c79f7 --- /dev/null +++ b/eBook/examples/chapter_3/gocomp @@ -0,0 +1,9 @@ +#!/bin/bash +FILES=~/goprograms/compiletest/*.go +for f in $FILES +do + echo "Processing $f file..." + # take action on each file. $f stores current file name + # cat $f + 6g $f >> compout +done diff --git a/eBook/examples/chapter_3/gocomp.bat b/eBook/examples/chapter_3/gocomp.bat new file mode 100644 index 0000000..4c9770c --- /dev/null +++ b/eBook/examples/chapter_3/gocomp.bat @@ -0,0 +1,2 @@ +FOR %%X in (*.go) DO 8g %%X >> compout + diff --git a/eBook/examples/chapter_3/run.cmd b/eBook/examples/chapter_3/run.cmd new file mode 100644 index 0000000..9b47375 --- /dev/null +++ b/eBook/examples/chapter_3/run.cmd @@ -0,0 +1,9 @@ +set GOROOT=E:\Go\GoforWindows\gowin32_release.r59\go +set GOBIN=$GOROOT\bin +set PATH=%PATH%;$GOBIN +set GOARCH=386 +set GOOS=windows +echo off +8g %1.go +8l -o %1.exe %1.8 +%1