go语言为什么调用c语言 go语言调用so

如何在golang 中调用c的静态库或者动态库Cgo 使得Go程序能够调用C代码. cgo读入一个用特别go语言为什么调用c语言的格式写go语言为什么调用c语言的Go语言源文件, 输出Go和C程序, 使得C程序能打包到Go语言的程序包中.
举例说明一下. 下面是一个Go语言包, 包含go语言为什么调用c语言了两个函数 -- Random 和 Seed -- 是C语言库中random和srandom函数的马甲.
package rand
/*
#include stdlib.h
*/import "C"func Random() int {return int(C.random())}func Seed(i int) {C.srandom(C.uint(i))}
go语言为什么调用c语言我们来看一下这里都有什么内容. 开始是一个包的导入语句.
rand包导入了"C"包, 但go语言为什么调用c语言你会发现在Go的标准库里没有这个包. 那是因为C是一个"伪包", 一个为cgo引入的特殊的包名, 它是C命名空间的一个引用.
rand 包包含4个到C包的引用: 调用 C.random和C.srandom, 类型转换 C.uint(i)还有引用语句.
Random函数调用libc中的random函数, 然后回返结果. 在C中, random返回一个C类型的长整形值, cgo把它轮换为C.long. 这个值必需转换成Go的类型, 才能在Go程序中使用. 使用一个常见的Go类型转换:
func Random() int {return int(C.random())}
这是一个等价的函数, 使用了一个临时变量来进行类型转换:
func Random() int {var r C.long = C.random()return int(r)}
Seed函数则相反. 它接受一个Go语言的int类型, 转换成C语言的unsigned int类型, 然后传递给C的srandom函数.
func Seed(i int) {C.srandom(C.uint(i))}
需要注意的是, cgo中的unsigned int类型写为C.uint; cgo的文档中有完整的类型列表.
这个例子中还有一个细节我们没有说到, 那就是导入语句上面的注释.
/*
#include stdlib.h
*/import "C"
Cgo可以识别这个注释, 并在编译C语言程序的时候将它当作一个头文件来处理. 在这个例子中, 它只是一个include语句, 然而其实它可以是使用有效的C语言代码. 这个注释必需紧靠在import "C"这个语句的上面, 不能有空行, 就像是文档注释一样.
Strings and things
与Go语言不同, C语言中没有显式的字符串类型. 字符串在C语言中是一个以0结尾的字符数组.
Go和C语言中的字符串转换是通过C.CString, C.GoString,和C.GoStringN这些函数进行的. 这些转换将得到字符串类型的一个副本.
下一个例子是实现一个Print函数, 它使用C标准库中的fputs函数把一个字符串写到标准输出上:
package print// #include stdio.h// #include stdlib.himport "C"import "unsafe"func Print(s string) {cs := C.CString(s)C.fputs(cs, (*C.FILE)(C.stdout))C.free(unsafe.Pointer(cs))}
在C程序中进行的内存分配是不能被Go语言的内存管理器感知的. 当你使用C.CString创建一个C字符串时(或者其它类型的C语言内存分配), 你必需记得在使用完后用C.free来释放它.
调用C.CString将返回一个指向字符数组开始处的指错, 所以在函数退出前我们把它转换成一个unsafe.Pointer(Go中与C的void 等价的东西), 使用C.free来释放分配的内存. 一个惯用法是在分配内存后紧跟一个defer(特别是当这段代码比较复杂的时候), 这样我们就有了下面这个Print函数:
func Print(s string) {cs := C.CString(s)defer C.free(unsafe.Pointer(cs))C.fputs(cs, (*C.FILE)(C.stdout))}
构建 cgo 包
如果你使用goinstall, 构建cgo包就比较容易了, 只要调用像平常一样使用goinstall命令, 它就能自动识别这个特殊的import "C", 然后自动使用cgo来编译这些文件.
如果你想使用Go的Makefiles来构建, 那在CGOFILES变量中列出那些要用cgo处理的文件, 就像GOFILES变量包含一般的Go源文件一样.
rand包的Makefile可以写成下面这样:
include $(GOROOT)/src/Make.inc
TARG=goblog/rand
CGOFILES=\rand.go\include $(GOROOT)/src/Make.pkg
然后输入gomake开始构建.
更多 cgo 的资源
cgo的文档中包含了关于C伪包的更多详细的说明, 以及构建过程. Go代码树中的cgo的例子给出了更多更高级的用法.
一个简单而又符合Go惯用法的基于cgo的包是Russ Cox写的gosqlite. 而Go语言的网站上也列出了更多的的cgo包.
最后, 如果你对于cgo的内部是怎么运作这个事情感到好奇的话, 去看看运行时包的cgocall.c文件的注释吧.
golang中调用c的正确姿势工程结构如上图所示go语言为什么调用c语言 , 我们需要实现go语言为什么调用c语言的目标是在go文件中调用c文件
foo.c如下go语言为什么调用c语言:
foo.go如下
foo.h如下:
编译过程如下:
1、先将c文件编译为.o文件 , 然后生成动态链接库.dylib文件
(1) clang -c foo.c
(2 clang -shared foo.o -o libfoo.dylib
2、在上述go语言为什么调用c语言的动态链接库生成之后,在foo.go中添加动态链接命令:#cgo LDFLAGS: -L./ -lfoo
需要注意的是
中间不能有空格
go语言如何调用c函数直接嵌入c源代码到go代码里面
package main
/*
#include stdio.h
void myhello(int i) {
printf("Hello C: %d\n", i);
}
*/
import "C"
import "fmt"
func main() {
C.myhello(C.int(12))
fmt.Println("Hello Go");
}
需要注意的是C代码必须放在注释里面
import "C"语句和前面的C代码之间不能有空行
运行结果
$ go build main.go./main
Hello C: 12
Hello Go
分开c代码到单独文件
嵌在一起代码结构不是很好看,很多人包括我,还是喜欢把两个分开,放在不同的文件里面,显得干净,go源文件里面是go的源代码 , c源文件里面是c的源代码 。
$ ls
hello.chello.hmain.go
$ cat hello.h
void hello(int);
$ cat hello.c
#include stdio.h
void hello(int i) {
printf("Hello C: %d\n", i);
}
$ cat main.go
package main
// #include "hello.h"
import "C"
import "fmt"
func main() {
C.hello(C.int(12))
fmt.Println("Hello Go");
}
编译运行
$ go build./main
Hello C: 12
Hello Go
编译成库文件
如果c文件比较多,最好还是能够编译成一个独立的库文件 , 然后go来调用库 。
$ find mylib main
mylib
mylib/hello.h
mylib/hello.c
main
main/main.go
编译库文件
$ cd mylib
# gcc -fPIC -shared -o libhello.so hello.c
编译go程序
$ cd main
$ cat main.go
package main
// #cgo CFLAGS: -I../mylib
// #cgo LDFLAGS: -L../mylib -lhello
// #include "hello.h"
import "C"
import "fmt"
func main() {
C.hello(C.int(12))
fmt.Println("Hello Go");
}
$ go build main.go
运行
$ export LD_LIBRARY_PATH=../mylib
$ ./main
Hello C: 12
Hello Go
在我们的例子中 , 库文件是编译成动态库的 , main程序链接的时候也是采用的动态库
$ ldd main
linux-vdso.so.1 =(0x00007fffc7968000)
libhello.so = ../mylib/libhello.so (0x00007f513684c000)
libpthread.so.0 = /lib64/libpthread.so.0 (0x00007f5136614000)
libc.so.6 = /lib64/libc.so.6 (0x00007f5136253000)
/lib64/ld-linux-x86-64.so.2 (0x000055d819227000)
理论上讲也是可以编译成整个一静态链接的可执行程序,由于我的机器上缺少静态链接的系统库,比如libc.a,所以只能编译成动态链接 。
【go语言为什么调用c语言 go语言调用so】go语言为什么调用c语言的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于go语言调用so、go语言为什么调用c语言的信息别忘了在本站进行查找喔 。

    推荐阅读