• 技术文章 >后端开发 >Golang

    经验分享:golang与c语言是如何相互调用!

    藏色散人藏色散人2021-11-25 14:55:35转载57
    本文由go语言教程栏目给大家介绍golang与c语言是如何相互调用 ,希望对需要的朋友有所帮助!

    go语言与c语言的相互调用

    最近由于工作原因,需要实现go语言与c语言的相互调用。由于go语言与c语言有着千丝万缕的暧昧关系,两者之间的调用可以通过语言层面实现。下文是对此的总结。

    go语言调用c语言

    以下为一个简短的例子:

    package main
    
    // #include <stdio.h>
    // #include <stdlib.h>
    /*
    void print(char *str) {
        printf("%s\n", str);
    }
    */
    import "C"
    
    import "unsafe"
    
    func main() {
        s := "Hello Cgo"
        cs := C.CString(s)
        C.print(cs)
        C.free(unsafe.pointer(cs))
    }

    与“正常”的go代码相比,上述代码有几处“特殊”的地方:

    • 在开头的注释中出现了c语言头文件的include字样

    • 在注释中定义了c语言函数print

    • import了一个名为C的“包”

    • 在main函数中调用了上述定义的c语言函数print

    首先,go源码文件中的c语言代码是需要用注释包裹的,就像上面的include头文件以及print函数定义;其次,import "C"这个语句是必须的,而且其与上面的c代码之间不能用空行分隔,必须紧密相连。这里的”C“不是包名,而是一种类似名字空间的概念,或可以理解为伪包,c语言所有语法元素均在该伪包下面;最后,访问c语法元素时都要在其前面加上伪包前缀,比如C.uint和上面代码中的C.print、C.free等。

    更详细的在go中调用c语言的用法可以参考Go与C语言的互操作,本文不再一一细述。

    在上面的例子中,c语言是内嵌在go代码中的,如果代码量更大更复杂的话,这显然是很不”专业“的。那么,是否可以将c语言代码从go代码中分离出去,单独定义呢?答案是肯定的,可以通过共享库的方式实现。

    cgo提供了#cgo指示符可以指定go源码在编译后与哪些共享库进行链接。例子如下:

    // hello.go
    package main
    
    // #cgo LDFLAGS: -L ./ -lhello
    // #include <stdio.h>
    // #include <stdlib.h>
    // #include "hello.h"
    import "C"
    
    func main() {
        C.hello()
    }
    
    // hello.c
    #include "hello.h"
    
    void hello()
    {
        printf("hello, go\n");
    }
    
    // hello.h
    extern void hello();

    其中在hello.go中,#cgo指示符后面添加LDFLAGS: -L ./ -lhello,作用是在go代码编译时,指定在当前目录查找so库并进行链接。

    因此,只需要把hello.c编译成动态库,再编译go代码,即可在运行go代码的时候调用共享库中的c语言函数。指令如下:

    • gcc -fPIC -o libhello.so hello.c

    • go build -o hello

    • ./hello

    c语言调用go语言

    与在go中调用c源码相比,在c中使用go函数的场合较少。因为一般来说,采用高级语言作为粘合剂调用低级语言能充分发挥各自的特点,而用低级语言调用高级语言反而有可能降低低级语言的性能优势,在go中,可以使用”export + 函数名“来导出go函数为c代码所用,看一个简单的例子:

    // hello.go
    package main
    
    import "C"
    
    import "fmt"
    
    // export Go2C
    func Go2C() {
        fmt.Println("hello, C")
    }

    可通过go build的编译选项,将go代码编译成共享库以供c代码调用。注意,编译so库时必须存在main及main函数(即使main函数为空)。编译指令如下:go build -v -x -buildmode=c-shared -o libhello.so hello.go

    编译成功后,只需在c代码中引入新生成的头文件及编译时链接动态库即可实现go函数的调用。代码如下:

    // hello.c
    #include <stdio.h>
    #include "libhello.h"
    
    int main()
    {
        Go2C();
        return 0;
    }

    通过gcc -o hello -L. -lhello,即可编译成可执行程序。注意,运行前必须确定共享库运行时查找路径中存在需要链接的共享库,可通过将so库路径放到/usr/lib或者修改环境变量LD_LIBRARY_PATH。

    小结

    go语言可以通过内嵌c代码的形式调用c语言,也可以通过调用共享库函数的方式实现;至于c语言调用go函数,则可以通过go build将go代码编译成共享库提供给c代码使用。注意,本文中的共享库均为动态共享库,至于静态共享库则未曾实验,有兴趣的可以实现一下。

    以上就是经验分享:golang与c语言是如何相互调用!的详细内容,更多请关注php中文网其它相关文章!

    声明:本文转载于:segmentfault,如有侵犯,请联系admin@php.cn删除
    专题推荐:c golang
    上一篇:介绍kafka和zookeeper是如何安装的 下一篇:go module是怎么使用本地包的(附示例)
    VIP会员

    相关文章推荐

    • 分析Golang的WaitGroup陷阱并解决问题• 聊聊Golang进程守护Supervisor• 如何在Mac环境下配置 Golang 环境• Golang和Lua相遇会擦出什么火花?

    全部评论我要评论

  • 取消发布评论发送
  • 1/1

    PHP中文网