Go 语言封装C语言源文件的方法详解和实例 / Go cgo使用方法

本文实践 go 语言引用 c 源文件,通过 go 语言封装的实例,在嵌入式开发过程中,
此方法可以解决很多实际问题。

自定义包的步骤

第一步

编写包的程序,本文以go 调用 c 语言为例,在 GOROOT/src 下建立 util包 文件夹,内容如下:
robot@ubuntu:/usr/local/go/src/util$ ls
go.mod  util.c  util.go  util.h
robot@ubuntu:/usr/local/go/src/util$ cat util.h 
int cSum(int x, int y);
robot@ubuntu:/usr/local/go/src/util$ cat util.c
#include "util.h"

int cSum(int x, int y){
	return (x+y);
}
robot@ubuntu:/usr/local/go/src/util$ cat util.go 
package util
/*
#include "util.h"
*/
import "C"

import "log"

func GoSum(x, y int) int {
	z := int(C.cSum(C.int(x), C.int(y)))
	log.Printf("goSum rs:%d\n",z)
	return z
}
robot@ubuntu:/usr/local/go/src/util$ cat go.mod 
module util

go 1.15
robot@ubuntu:/usr/local/go/src/util$ go build .		//编译包
robot@ubuntu:/usr/local/go/src/util$ go install     //安装包

包名称与文件夹名称最优是同名,在程序中import package 时,和调用包内容名称是一致的,利用包的管理。

第二步

调用自定义包,工作路径及内容如下:
robot@ubuntu:~/go-workspace/src/project/package$ ls
go.mod  main.go  pkg
robot@ubuntu:~/go-workspace/src/project/package$ cat main.go 
package main

import "fmt"
import "util"		//调用自定义包,导入的是包的文件夹名称

func main() {
	res := util.GoSum(12,3)
	fmt.Printf("This is main,res: %d \n",res)
}

robot@ubuntu:~/go-workspace/src/project/package$ cat go.mod 	// go mod init pkg 产生的 module pkg 内容
module pkg

go 1.15
robot@ubuntu:~/go-workspace/src/project/package$ go build .     // 使用 module 管理源码时,可以使用 go build . 编译生成 pkg包名称可执行文件
robot@ubuntu:~/go-workspace/src/project/package$ ./pkg 			// 执行
2021/08/18 23:58:50 goSum rs:15
This is main,res: 15 
robot@ubuntu:~/go-workspace/src/project/package$ 

我们可以总结以下几点:

(1)import语句使用的是文件夹的名称

(2)文件夹的名称和package的名称不一定相同,为了更换管理包我们一般采用文件夹与包名称同名

(3)调用自定义包使用package名称.函数名的方式

例如上面使用的util.GoSum(),用go把C 语言的调用封装,此方式可以把常用的 C语言代码封装成包。

(4)自定义包的调用和源码文件名没有关系

例如上面的util.go文件,如果改成util_c.go,程序也能正常编译。

实验过程中产生错误信息

~/go-workspace/src/project/cgo/c-util$ go build util.go 
# command-line-arguments
./util.go:12:6: could not determine kind of name for C.Sum

// 切记!!! 在注释和import”C”之间不能有空行

:~/go-workspace/src/project/cgo/c-util$ go build util.go 
# command-line-arguments
./util.go:12:2: cannot use x (type _Ctype_int) as type int in return argument

Go中 C原生的数值类型

数值类型 :

C.char, 
C.schar (signed char), 
C.uchar (unsigned char), 
C.short, 
C.ushort (unsigned short), 
C.int, C.uint (unsigned int), 
C.long, 
C.ulong (unsigned long), 
C.longlong (long long), 
C.ulonglong (unsigned long long), 
C.float, 
C.double

指针类型

  • 原生数值类型的指针类型可按Go语法在类型前面加上,比如var p *C.int,而void比较特殊,用Go中的unsafe.Pointer表示。
  • 任何类型的指针值都可以转换为unsafe.Pointer类型,而unsafe.Pointer类型值也可以转换为任意类型的指针值。
  • unsafe.Pointer还可以与uintptr这个类型做相互转换。
  • 由于unsafe.Pointer的指针类型无法做算术操作,转换为uintptr后可进行算术操作。

字符串类型

  • C语言中并不存在正规的字符串类型,在C中用带结尾’\0’的字符数组来表示字符串;
  • 在Go中,string类型是原生类型,因此在两种语言互操作是势必要做字符串类型的转换。

通过C.CString函数,我们可以将Go的string类型转换为C的”字符串”类型,再传给C函数使用。

eg:
s := “Hello Cgo\n” 
cs := C.CString(s) 
C.print(cs)

数组类型

C语言中的数组与Go语言中的数组差异较大,后者是值类型,而C 数组与指针大部分场合都可以随意转换。
目前似乎无法直接显式的在两者之间进行转型,官方文档也没有说明。但我们可以通过编写转换函数,
将C的数组转换为Go的Slice(由于Go中数组是值类型,其大小是静态的,转换为Slice更为通用一些),
下面是数组转换的例子的链接

对于 cgo 相关例子内容,可以参考官方文档。www.golang.org

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值