// hello.go
package main
import "C"
func main() {
println("hello cgo")
}
import "C"
语句启用CGO特性,主函数只是通过Go内置的println
函数输出字符串,其中并没有任何和CGO相关的代码。虽然没有调用CGO的相关函数,但是go build
命令会在编译和链接阶段启动gcc编译器,这已经是一个完整的CGO程序了。// hello.go
package main
//#include <stdio.h>
import "C"
func main() {
C.puts(C.CString("Hello, World\n"))
}
import "C"
语句启用CGO特性,同时包含C语言的<stdio.h>
头文件。然后通过CGO包的C.CString
函数将Go语言字符串转为C语言字符串,最后调用CGO包的C.puts
函数向标准输出窗口打印转换后的C字符串。相比“Hello, World 的革命”一节中的CGO程序最大的不同是:我们没有在程序退出前释放C.CString创建的C语言字符串;还有我们改用puts函数直接向标准输出打印,之前是采用fputs向标准输出打印。
没有释放使用C.CString创建的C语言字符串会导致内存泄漏。但是对于这个小程序来说,这样是没有问题的,因为程序退出后操作系统会自动回收程序的所有资源。
// hello.go
package main
/*
#include <stdio.h>
static void SayHello(const char* s) {
puts(s);
}
*/
import "C"
func main() {
C.SayHello(C.CString("Hello, World\n"))
}
SayHello
函数是我们自己实现的之外,其它的部分和前面的例子基本相似。 我们也可以将SayHello
函数放到当前目录下的一个C语言源文件中(后缀名必须是.c)。因为是编写在独立的C文件中,为了允许外部引用,所以需要去掉函数的static
修饰符。// hello.c
#include <stdio.h>
void SayHello(const char* s) {
puts(s);
}
SayHello
函数,其它部分不变:/ hello.go
package main
//void SayHello(const char* s);
import "C"
func main() {
C.SayHello(C.CString("Hello, World\n"))
}
go run hello.go
或go build hello.go
的话,此处须使用go run "your/package"
或go build "your/package"
才可以。若本就在包路径下的话,也可以直接运行go run .
或go build .
既然SayHello函数已经放到独立的C文件中了,我们自然可以将对应的C文件编译打包为静态库或动态库文件供使用。如果是以静态库或动态库方式引用SayHello函数的话,需要将对应的C源文件移出当前目录(CGO构建程序会自动构建当前目录下的C源文件,从而导致C函数名冲突)
hello.h
头文件定义:// hello.h
void SayHello(const char* s);
hello.c
文件:// hello.c
#include "hello.h"
#include <stdio.h>
void SayHello(const char* s) {
puts(s);
}
hello.c
文件的开头,实现者通过#include "hello.h"
语句包含SayHello函数的声明,这样可以保证函数的实现满足模块对外公开的接口。C++
语言来重新实现这个C语言函数:// hello.cpp
#include <iostream>
extern "C" {
#include "hello.h"
}
void SayHello(const char* s) {
std::cout << s;
}
std::cout
输出流输出字符串。不过为了保证C++语言实现的SayHello函数满足C语言头文件hello.h定义的函数规范,我们需要通过extern "C"
语句指示该函数的链接符号遵循C语言的规则。使用更复杂的C++语言来实现SayHello函数
,当然我们也可以用汇编语言甚至Go语言来重新实现SayHello函数
// hello.h
void SayHello(/*const*/ char* s);
// hello.go
package main
import "C"
import "fmt"
//export SayHello
func SayHello(s *C.char) {
fmt.Print(C.GoString(s))
}
//export SayHello
指令将Go语言实现的函数SayHello导出为C语言函数。为了适配CGO导出的C语言函数,我们禁止了在函数的声明语句中的const修饰符。需要注意的是,这里其实有两个版本的SayHello函数:一个Go语言环境的;另一个是C语言环境的。cgo生成的C语言版本SayHello函数最终会通过桥接代码调用Go语言版本的SayHello函数package main
//#include <hello.h>
import "C"
func main() {
C.SayHello(C.CString("Hello, World\n"))
}
package main
//void SayHello(char* s);
import "C"
import (
"fmt"
)
func main() {
C.SayHello(C.CString("Hello, World\n"))
}
//export SayHello
func SayHello(s *C.char) {
fmt.Print(C.GoString(s))
}
// +build go1.10
package main
//void SayHello(_GoString_ s);
import "C"
import (
"fmt"
)
func main() {
C.SayHello("Hello, World\n")
}
//export SayHello
func SayHello(s string) {
fmt.Print(s)
}
原文:https://www.cnblogs.com/binHome/p/12625764.html