Golang与C互用以及调用C的so动态库和a静态库

本文介绍了Golang如何与C代码互用,包括在Golang中嵌入C代码以及调用C的动态库so和静态库a。详细阐述了编译过程、代码结构,并通过实例探讨了C库与Golang交互时的注意事项,特别是关于printf和stdout缓冲区的行为差异。

Golang与C的关系非常密切,下面主要介绍在Golang中使用C。
##一. Golang中嵌入C代码

  1 package main                                                                                                                    
  2  
  3 //#include <stdio.h>
  4 //#include <stdlib.h>
  5 /*
  6 void Hello(char *str) {
  7     printf("%s\n", str);
  8 }
  9 */
 10 import "C" //假设把C当成包,其实有点类似C++的名字空间
 11 import "unsafe" //C指针的使用,在C代码中申请的空间,GC垃圾回收机制不会管理,所以需要自己手动free申请的空间
 12  
 13 func main() {
 14     s := "Hello Cgo"
 15     cs := C.CString(s)
 16     C.Hello(cs)
 17     C.free(unsafe.Pointer(cs))
 18 }

3,4行的注释也可以写/* */形式
第4行与第5行之间不能有空行,同样第9行与第10行之间也不
能有行,否则编译时cgo会报错:

jack@jack-VirtualBox:~/mygo/src/myC/tmp$ go run goc.go
# command-line-arguments
could not determine kind of name for C.Hello
could not determine kind of name for C.free

##Golang中调用C的动态库so
C库源程序代码:

  1 //foo.c                                                                                                                         
  2 #include <stdio.h>
  3  
  4 int Num = 8;
  5  
  6 void foo(){
  7     printf("I dont have new line.");
  8     printf("I have new line\n");
  9     printf("I have return\r");
 10     printf("I have return and new line\r\n");
 11 }
  1 //foo.h                                                                                                                         
  2 #ifndef __FOO_H
  3 #define __FOO_H
  4  
  5 #ifdef __cplusplus
  6 extern "C" {
  7 #endif
  8  
  9 extern int Num;
 10 extern void foo();
 11  
 12 #ifdef __cplusplus
 13 }
 14 #endif
 15  
 16 #endif

Go调用C库的代码:

  1 package main                                                                                                                    
  2  
  3 /*
  4 #cgo CFLAGS: -I.
  5 #cgo LDFLAGS: -L. -lfoo
  6 #include <stdio.h>
  7 #include <stdlib.h>
  8 #include "foo.h"
  9 */
 10 import "C"
 11 import "unsafe"
 12 import "fmt"
 13  
 14 func Prin(s string) {
 15     cs := C.CString(s)
 16     defer C.free(unsafe.Pointer(cs))
 17     C.fputs(cs, (*C.FILE)(C.stdout))
 18     //C.free(unsafe.Pointer(cs))
 19     C.fflush((*C.FILE)(C.stdout))
 20 }
 21  
 22 func main() {
 23     fmt.Println("vim-go")
 24     fmt.Printf("rannum:%x\n", C.random())
 25     Prin("Hello CC")
 26     fmt.Println(C.Num)
 27     C.foo()
 28 }

注意import "C"这行与第9行之间也不能有空格,原因同上编译会报错。
go与库、头文件的目录结构,以及编译:

jack@jack-VirtualBox:~/mygo/src/myC/sotest$go build cc.go //编译之后产生cc
jack@jack-VirtualBox:~/mygo/src/myC/sotest$ ls
cc  cc.go  foo.h  libfoo.so
jack@jack-VirtualBox:~/mygo/src/myC/sotest$ export LD_LIBRARY_PATH=./
jack@jack-VirtualBox:~/mygo/src/myC/sotest$ ./cc
vim-go
rannum:6b8b4567
Hello CC8
I dont have new line.I have new line
I have return and new line

如果c库的程序改为下面这样:

  1 //foo.c                                                                                                                         
  2 #include <stdio.h>
  3  
  4 int Num = 8;
  5  
  6 void foo(){
  7     printf("I dont have new line.");
  8     //printf("I have new line\n");
  9     //printf("I have return\r");
 10     //printf("I have return and new line\r\n");
 11 }

此时,go中调用foo时没有任何反应,即不会输出,不会输出的原因是printf后面没有加换行符,但是如果加了8,9,10这些测试行后,第7行也会显示,原因是第10行最后有一个换行符,这个应该是向stdout输出时,字符流是放在buffer中,如果没有换行,buffer中的数据不会立即输出。在go调用C的测试程序中有写了一个测试小函数用来测试stdout,验证了没有fflush,stdout上不会显示输出信息。但平时在写C程序的时候,似乎没有这样的问题,这个是因为C的运行环境自动做了fflush的动作,这个可能是Golang的不足,也许golan表g认为这样做更好。这只是个人的分析,如有分析不对的地方,请跟贴,谢谢。

##Golang调用C的静态库a
所有源程序与动库演示代码类似,只是编译C库时,是用的静态编译,如下所示:

jack@jack-VirtualBox:~/mygo/src/myC$ ls
foo.c 
jack@jack-VirtualBox:~/mygo/src/myC$ gcc -c foo.c
foo.c foo.o
jack@jack-VirtualBox:~/mygo/src/myC$ ar -rv libfoo.a foo.o
foo.c foo.o libfoo.a

Go调用的代码与动态库一样,下面是目录结构:

jack@jack-VirtualBox:~/mygo/src/myC/atest$ ls
cc  cc.go  foo.h  libfoo.a
评论 10
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JXES智能生态系统

如文章对你有用,请作者喝个咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值