go调用c (c和go相互调用 CGO)

文章目录

    • 什么是cgo
      • 使用cgo带来的问题
      • 举例
      • 根据c自动生成go绑定代码

什么是cgo

golang中调用C代码
参考URL: https://www.jianshu.com/p/871727c2a82c

在很多场景下,在Go的程序中需要调用c函数或者是用c编写的库(底层驱动,算法等,不想用Go语言再去造一遍轮子,复用现有的c库)。
那么该如何调用呢?Go可是更好的C语言啊,当然提供了和c语言交互的功能,称为cgo!

CGO 提供了 golang 和 C 语言相互调用的机制。某些第三方库可能只有 C/C++ 的实现,完全用纯 golang 的实现可能工程浩大,这时候 CGO 就派上用场了。可以通 CGO 在 golang 在调用 C 的接口,C++ 的接口可以用 C 包装一下提供给 golang 调用。

使用cgo带来的问题

cgo 和 Go 语言是两码事
参考URL: https://www.oschina.net/translate/cgo-is-not-go
英文原文:https://dave.cheney.net/2016/01/18/cgo-is-not-go

复杂的构造:
用户还要安装C编译器,而不是只安装Go编译器。他们同时还需要安装你项目所依赖的C库,所以你同时还要承担这些支持的成本。

交叉编译不支持:
在默认情况下cgo是不允许交叉编译的。 如果你的项目是纯Go的。 当你混合了C库的依赖, 你或者不得不放弃交叉编译你的产品,或者不得不花时间在寻找并且维护C的交叉编译工具链来达成你的目标。如果你的产品依赖C库,不仅你要面临以上描述的所有交叉编译问题,你还要确保你所依赖的C代码在Go所支持的新平台上能可靠运行——你必须要做这些运用C/Go混合提供的有限的调试。

一些go工具失效:
Go有一些伟大的工具;有竞态分析、性能分析、覆盖率、模糊测试和其他源代码分析工具。这些中没有任何一个能够跨越cgo屏障。相反地,像Valgrind这样的优秀工具不理解Go的调用约定和堆栈布局。

性能问题:
C代码和Go代码生存在两个不同的宇宙中,cgo横贯了他们两个之间的分界线。这个过渡并不是自由的,它取决于它在你代码中的位置,花费可能是无足轻重的,也可能是巨额的。

部署变得更复杂:
原本只有一个静态二进制文件,这是Go的法宝,它引领Go成为了远离虚拟机和运行管理的典型代表。使用cgo,你就要放弃这些。编译一个完全静态的Go程序是可行的,但是如果你的项目中包含了cgo那将是绝不简单的,其后果将影响一整个构建和部署的生命周期。

总结:原作者说的情况确实存在,就看项目业务代码需求,引入cgo破坏调试,部署就比较麻烦,但是有些场景你确实需要c实现,考虑cgo。

举例

https://studygolang.com/articles/10163
参考URL: https://studygolang.com/articles/10163
golang cgo 使用总结
参考URL:https://blog.csdn.net/darlingtangli/article/details/84198859

  1. 代码可以写入到go文件中
    C代码可以写入到go文件中,要写在最前面,C代码用注释的写法,最后import “C”;

在Go代码部分直接调用该c函数hi()

package main

import "fmt"

/*
#include 

void hi() {
    printf("hello world!\n");
}
*/
import "C" //这里可看作封装的伪包C, 这条语句要紧挨着上面的注释块,不可在它俩之间间隔空行!

func main() {
    C.hi()
    fmt.Println("Hi, vim-go")
}
  1. include头文件、动态链接库的写法:
package main

import "fmt"

/*
#cgo CFLAGS: -I./
#cgo LDFLAGS: -L./ -lhi
#include "hi.h" //非标准c头文件,所以用引号
*/
import "C"

func main() {
    C.hi()
    fmt.Println("Hi, vim-go")
}

CFLAGS中的-I(大写的i) 参数表示.h头文件所在的路径
LDFLAGS中的-L(大写) 表示.so文件所在的路径 -l(小写的L) 表示指定该路径下的库名称,比如要使用libhi.so,则只需用-lhi (省略了libhi.so中的lib和.so字符)表示。

头文件路径和库文件路径写死的话,一旦第三方库的安装路径变化了,Golang的代码也要跟着变化,就会很麻烦。这时可以使用cgo命令中使用pkg-config

当在Go中使用了以上的方法后,就要求主机(或者云服务器)上必须有相应的.so文件,如果不存在就会链接报错,导致程序退出。

总结: go语言可以通过内嵌c代码的形式调用c语言,也可以通过调用共享库函数的方式实现。

import “C” //假设把C当成包,其实有点类似C++的名字空间
import “unsafe” //C指针的使用,在C代码中申请的空间,GC垃圾回收机制不会管理,所以需要自己手动free申请的空间

根据c自动生成go绑定代码

官网: https://github.com/xlab/c-for-go

Automatic C-Go Bindings Generator for Go Programming Language

This project allows to reuse existing C/C++ libraries in your Go applications, by automatically creating c-go bindings for a given set of C headers and the manifest file. We believe in component-based software engineering and think that reusing C/C++ code in Go applications could bring a huge boost to developer’s productivity and system’s performance. Read more about the motivation: top reasons to use bindings.
Go语言的自动C-Go绑定生成器

该项目允许在GO应用程序中重用现有C/C++库,通过自动为给定的C标题集和清单文件创建C-GO绑定。我们相信基于组件的软件工程,并认为在GO应用程序中重用C/C++代码可以极大地提高开发者的生产力和系统的性能。阅读更多关于动机的信息:使用绑定的主要原因。
go调用c (c和go相互调用 CGO)_第1张图片

The only component required to produce a Go package that will wrap the source C/C++ code is the YAML manifest file that defines parsing, translation and generation rules. The manifest can have just a few lines, however in order to match Go’s naming conventions and provide enough tips for type conversions it usually contains about 100 lines, which is still better than producing tens of thousands lines of Go code by hand.

The resulting bindings are as low-level as C code, i.e. it would require knowledge of memory management to carefully use the resulting code, however no more C code is needed to make things done. Eventually some functions can be replaced manually with pure-Go analogs. Also usually a high-level wrapper is created by hand, to introduce Object Oriented Design into API, manage inner state and memory, thus making things safe and lifting the mental overhead.

Full documentation is available at https://github.com/xlab/c-for-go/wiki
生成打包源代码C/C++代码的GO包所需的唯一组件是定义解析、翻译和生成规则的YAML清单文件。清单可以只有几行,但是为了匹配Go的命名约定并为类型转换提供足够的提示,它通常包含大约100行,这比手工生成上万行Go代码要好。

结果绑定与C代码一样是低级的,也就是说,它需要内存管理知识来仔细使用结果代码,但是不需要更多的C代码来完成任务。最终,一些功能可以手动替换为纯Go模拟。通常也会手工创建一个高级包装器,将面向对象的设计引入到API中,管理内部状态和内存,从而使事情变得安全并提高心理负担。

完整的文档可在https://github.com/xlab/c-for-go/wiki

这个项目曾经是一个辅助工具,用来创建我想在我的应用程序中使用的C库的CGo绑定。其思想是扫描所提供的C头文件,查找结构、类型和函数定义,并将它们的名称转换为惯用的Go文件,为CGo调用准备样板代码,等等。现在c-for-go是一个功能齐全的绑定生成器,它可以完成95%的工作,它允许任何想在代码中使用任何c库的人在不到一个小时的时间内不用编写一行代码。

根据c生成 go绑定代码,生成的代码中开头有标识,如下:
// WARNING: This file has automatically been generated // Code generated by https://git.io/c-for-go. DO NOT EDIT.

你可能感兴趣的:(Go)