cgo编程

本文详细介绍了Go语言如何通过cgo工具调用C语言函数,并导出C动态库。讲解了cgo的快速入门,包括内存管理、函数导出、类型转换等关键点。此外,还探讨了cgo在不同系统下的行为以及类型转换的注意事项,如Go语言字符串在C语言中的表示。最后,提到了cgo在本地和交叉编译时的环境变量配置。
摘要由CSDN通过智能技术生成

简介:

go语言通过自带的一个叫cgo的工具来支持c语言函数调用,同事我们可以用Go语言导出c动态库给其他语言使用。

2.1 快速入门

1、没有释放使用C.CString创建的C语言字符串会导致内存泄漏。

2、需要通过extern "C"语句指示该函数的链接符号遵循C语言的规则。

3、cgo不仅用于Go语言中调用C语言函数,还可以用于导出Go语言函数给C函数调用。

4、通过CGO//export SayHello指令将Go语言实现的函数SayHello()导出为C语言函数。为了适配

CGO导出的C语言函数,我们禁止了在函数的声明语句中的const修饰符。需要注意的是,这里其实有

两个版本的SayHello函数的版本:一个go语言环境的,一个是C语言环境的。

cgo生成的C语言版本的SayHello函数最终会通过桥接代码调用Go语言版本的SayHello函数。

5、在Go1.10中CGO新增加了一个_GoString_预定义的C语言类型,用来表示Go语言字符串。

2.2 CGO基础

1、开头的注释中写了要调用的C函数和相关的头文件,头文件被include之后里面所有的C语言元素都会被

加入“C”这个虚拟的包中。

2、通过虚拟的C包导入的C语言符号并不需要以大写字母开头,不受Go语言的导出规则约束。

3、不同的Go语言包引入的虚拟C包之间的类型是不能通用的。这导致从他们延伸出来的go类型也是不同的类型

一个包如果在公开的接口中直接使用了*C.char等类似的虚拟C包的类型,其他go包无法直接使用这些类型的。

除非这个go包同时也提供了*C.char类型的构造函数。

4、#cgo语句在import "C"语句前的注释中可以通过#cgo语句设置编译阶段和链接阶段的相关

参数。在库文件的检索目录中可以通过$(SRCDIR)变量表示当前包目录的绝对路径。

5、#cgo语句还支持条件选择,当满足某个操作系统和某个CPU架构类型时,后面的编译选项生效。

6、不同的系统下CGO对应着不同的C代码,可用#CGO语句定义不同的宏。

7、build标志条件编译,

2.3类型转换

1、go访问c的符号时,一般是通过虚拟的“C”包访问的,有些c语言的类型是由多个关键字组成的,

因此CGO为C语言的基础数字类型都提供了相应转换规则。注意点:c语言中int、short等类型没有

明确定义内存大小,但是CGO中他们内存的大小确定的。在CGO中,c的int和long都是对应4个

字节的。

2、在c语言中访问go语言的int类型,可以通过GoInt类型访问,GoInt在CGO生成_cgo_export.h头

文件中定义。

3、go字符串和切片,在_cgo_export.h头文件中还会为Go语言的字符串、切片、字典、接口和通道

等特有的数据类型生成对应的C语言类型。只有字符串和切片在CGO中有一定的使用价值。因为CGO

为其提供了辅助函数。使用GoString类型会对_cgo_export.h产生依赖,go1.10对go字符串增加了

_GoString_预定义类型,减少对_cgo_export.h的依赖。同事go1.10还增加对_GoString_操作的辅助

函数。

4、结构体、联合和枚举类型,c语言结构体中的位字段对应的成员无法在go语言中访问,

如果需要操作位字段成员,需要通过在c语言中定义辅助函数来完成。也无法访问零长的数组

成员。在c语言中,无法直接访问go语言定义的结构体类型。

5、数组、字符串和切片,

 

总结:

1、go语言通过自带的cgo工具来支持对c语言函数的调用,同时也可以使用go语言导出C动态库

给其他语言使用。

2、代码通过import "C"来开启cgo特性,go build命令在编译和链接阶段启动gcc编译器。

3、包含<stdio.h>头文件通过C虚拟包的C.CString(...)来构造字符串,C.CString(...)调用

malloc克隆字符串,使用结束后需要调用C.Free(...)来释放内存。

4、go调用自定义的C接口函数需要删除static,否则外部无法使用。

5、go调用的c函数可以以静态库和动态库的形式被go使用。

6、c函数实现文件并不是一定要以.c文件,可以以.cpp文件存在,但是一定要加入extern "C" 告诉

C++编译器要按照C的函数编译方式编译,指示函数的链接符号遵循C语言的规则,符号C语言API

接口编程规范。CGO不支持C++语法的根本原因是C++至今没有一个二进制接口规范。

7、可以用go实现C语言的函数,可以通过CGO的//export functionname指令将Go语言实现的函数

导出为C语言函数。此时会产生两个版本的函数,一个是go语言环境的,一个是c语言环境的。

cgo生成的c语言版本的函数会通过桥接代码调用go语言版本的函数。

8、在go1.10中cgo新增了一个_GoString_预定义的C语言类型,用来表示go语言字符串。

9、cgo在本地构建时cgo默认是开启的环境CGO_ENABLED:1,交叉构建时cgo默认时禁止的

CGO_ENABLED:0。在环境变量为1,然后通过import "C"语句来启用CGO特性。

10、import “C”语句紧邻这行语句前面的注释是一种特殊语法,里面包含正常C的代码。

在确保CGO启用的情况下,还可以在当前目录下包含C/c++对应的源文件。import "C"需要单独一行。

11、数值类型go访问c语言中的符号,一般是通过虚拟包“C”包访问的,如C.int对应c语言的int类型。

有些c语言的类型是多个关键字组成的,但是通过虚拟包“C”访问c语言类型不能有空格。cgo为c语言的

基础类型做了规则转换。如:C.uint对应C语言的unsigned int。

12、在c中int、short等类型没有明确定义大小,但是在cgo中内存大小是确定的,都是4个字节。

13、c语言中访问go语言的类型,每个基本的go数值类型都定义了对应的C语言类型,一般以单词Go

为前缀。除了GoInt和GoUint之外,我们并不直接推荐访问GoInt32、GoInt64等类型。更好的是

通过C语言的C99标准引入<stdint.h>头文件。

14、go字符串和切片,

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值