本文由golang教程栏目给大家介绍关于CGO实战项目中常用的数据转换和使用,希望对需要的朋友有所帮助!
前言
需要部署好相关环境和具备基本的知识点,这并非是一篇科普的文章,主要是针对实际项目中用到的类型转换和使用,针对动态库的函数调用参数传递和接收
1、GO环境,启动支持CGO
2、事先安装g++
3、看得懂GO和C的语法
4、最好会基本的makefile或者shell语法(表示我不懂,是个菜鸡,只会看个大概)主要是自己调试C需要用到
如果大家是一清二白的,请点击扫盲链接:chai2010.cn/advanced-go-programmin...
基本数据类型一览
由于GO支持 C语言的调用,所以只列出了和C的转换,至于C++,需要转换成C语言才可以成功调用。需要注意的是:每个C的变量都是限定在一个包内使用的,如果想跨包使用,请用GO封装一层,否则会提示调用错误,找不到这个C变量。
项目中用到的数据类型转换
go的string转换成C
C的字符串就是一个字符数组的特例,简单的说就是一个字符数组以0结尾的数组就是字符串,所以不属于基本数据类型 。
C.CString是调用C的标准库,申请了新的内存空间,需要调用C.free释放,否则会内存泄漏。
var deviceIp string cdeviceIp := C.CString(deviceIp) defer C.free(unsafe.Pointer(cdeviceIp))
C的char * /char[] 转换成go的string
调用C的标准库 C.GoString,这个函数不会产生新的内存空间,创建的是一个副本,也不会释放内存空间。
C的字节数组转Go的string
比方说C的类型是:BYTE sSerialNumber[SERIALNO_LEN];
获取的方式就是利用append添加字节到字符串
serialNo := make([]byte, 0) for _, v := range sSerialNumber { if v != 0 { serialNo = append(serialNo, byte(v)) } }
注意前面提到的字符数组和字符串的区别。
Go的string转C的字符数组
类型:CHAR szKeyFilePath[PU_CERT_FILE_PATH_MAX];
var keyFilePath = "/home/docker/path/file.jpg" for i, b := range keyFilePath { szKeyFilePath[i] = C.CHAR(b) }
联合体的数据获取
接华为摄像头的数据回调的时候有联合体类型数据的获取,当作普通结构体获取的时候编译会一直提示找不到这个结构体,后面不得已,在C代码里面获取到联合体的数据之后,转换成基本数据类型,再重新Go调用。贴一个代码片断,人脸识别回调获取的数据。不用纠结前后文,看数据类型的获取就好。
void CGopfFaceSnapCallBack(CHAR *szBuffer, LONG lSize, void *pUsrData) { PU_META_DATA *pstMetaData = 0; int ret = Wrapper_IVS_User_GetMetaData(szBuffer, lSize, TARGET, &pstMetaData); if (ret == PU_FALSE ){ return ; } PU_UserData *pstMetaUserData = pstMetaData->pstMetaUserData; char name[100]={0}; char cardID[100]={0}; for(UINT uIndex = 0; uIndex < pstMetaData->usValidNumber; ++uIndex){ //printf("pstMetaData eType : %x\n", pstMetaUserData[uIndex].eType); if (pstMetaUserData[uIndex].eType == FACE_INFO){ strcpy(cardID, pstMetaUserData[uIndex].unMetaData.stFaceInfo.cardID); strcpy(name, pstMetaUserData[uIndex].unMetaData.stFaceInfo.name); printf("GopfFaceSnapCallBack unMetaData.stFaceInfo cardID : %s\n", pstMetaUserData[uIndex].unMetaData.stFaceInfo.cardID); printf("GopfFaceSnapCallBack unMetaData.stFaceInfo name : %s\n", pstMetaUserData[uIndex].unMetaData.stFaceInfo.name); GopfFaceSnapCallBack(pstMetaUserData[uIndex].unMetaData.stFaceInfo.cardID,pUsrData); break ; } } Wrapper_IVS_User_FreeMetaData(&pstMetaData); return ;}
如果这段代码换成Go的逻辑,直接在Go里面去读取的话会提示unMetaData 找不到定义。有其他成功读取方式的,还请告知。
C的回调函数的调用
1、先Go代码实现数据类型一致的函数,利用//export 导出为C函数,如果发现回调没进来,首先检查一下数据类型是否正确,再检查触发条件是否满足。这一步是为了在Go语言里面接收到C语言的回调数据,也就是回调后的数据是在这个函数里面获取。
2、CGO调用C函数,有同事说这一步可以不用,直接在Go里面调用第一步的函数就可以,我还没试过,公司祖传的代码就是这么写的,也就直接照用了。
3、在GO语言里面当作常用函数直接调用就好。
看代码示例:
C的函数声明:
typedef VOID (CALLBACK *pfRealDataCallBack)(CHAR *szBuffer, LONG lSize, VOID *pUsrData);
第一步的代码:
//export GopfRealDataCallBackfunc GopfRealDataCallBack(szBuffer *C.CHAR, lSize C.LONG, pUsrData unsafe.Pointer) { fmt.Println(szBuffer,lSize,pUsrData)}
第二步:
extern void GopfRealDataCallBack(CHAR *szBuffer, LONG lSize, void *pUsrData);void CGopfRealDataCallBack(CHAR *szBuffer, LONG lSize, void *pUsrData){ return GopfRealDataCallBack(szBuffer,lSize,pUsrData);}
第三步:C.pfRealDataCallBack(C.CGopfRealDataCallBack),需要在import C 上声明,否则调用不生效
void*和unsafe.Pointer
unsafe.Pointer号称是所有数据类型的转接桥梁,在语言层面两个可以认为等同的,当碰到void*可以用unsafe.Pointer来接收或者传递,具体类型的转换,需要根据实际类型做强转。比方说:
lpOutBuff := unsafe.Pointer(C.malloc(1024))
这个1024看实际情况修改,不是万能的。
结构体数组的传递
results := (*C.struct_name)(C.malloc(C.size_t(C.sizeof_struct_name * C.int(resLen)))) defer C.free(unsafe.Pointer(results))
struct_name换成具体的结构体名称,申请了空间要释放,GO检测不到C的部分。
结构体数组遍历获取元素数据
for i := 0; i < int(resLen); i++ { result := (*C.struct_name)(unsafe.Pointer(uintptr(unsafe.Pointer(results)) + uintptr(i*C.sizeof_struct_name))) }
struct_name换成具体的结构体名称,uintptr是元素内存地址,根据偏移量获取元素。go
for i := 0; i < int(resLen); i++ {
result := (*C.DetectFaceResult)(unsafe.Pointer(uintptr(unsafe.Pointer(results)) + uintptr(i*C.sizeof_DetectFaceResult)))
}
以上是详解CGO项目中常用的数据转换及使用的详细内容。更多信息请关注PHP中文网其他相关文章!

Go的"strings"包提供了丰富的功能,使字符串操作高效且简单。1)使用strings.Contains()检查子串。2)strings.Split()可用于解析数据,但需谨慎使用以避免性能问题。3)strings.Join()适用于格式化字符串,但对小数据集,循环使用 =更有效。4)对于大字符串,使用strings.Builder构建字符串更高效。

Go语言使用"strings"包进行字符串操作。1)拼接字符串使用strings.Join函数。2)查找子串使用strings.Contains函数。3)替换字符串使用strings.Replace函数,这些函数高效且易用,适用于各种字符串处理任务。

资助bytespackageingoisesential foreffited byteSemanipulation,uperingFunctionsLikeContains,index,andReplaceForsearchingangingAndModifyingBinaryData.itenHancesperformanceNandCoderAceAnibility,MakeitiTavitalToolToolToolToolToolToolToolToolToolForhandLingBinaryData,networkProtocols,networkProtocoLss,networkProtocols,andetFilei

Go语言使用"encoding/binary"包进行二进制编码与解码。1)该包提供binary.Write和binary.Read函数,用于数据的写入和读取。2)需要注意选择正确的字节序(如BigEndian或LittleEndian)。3)数据对齐和错误处理也是关键,确保数据的正确性和性能。

1)usebybytes.joinforconcatenatinges,2)bytes.bufferforincrementalWriter,3)bytes.indexorbytes.indexorbytes.indexbyteforsearching bytes.bytes.readereforrednerncretinging.isnchunk.ss.ind.inc.softes.4)

theencoding/binarypackageingoiseforporptimizingBinaryBinaryOperationsDuetoitssupportforendiannessessandefficityDatahandling.toenhancePerformance:1)usebinary.nativeendiandiandiandiandiandiandiandian nessideendian toavoid avoidByteByteswapping.2)

Go的bytes包主要用于高效处理字节切片。1)使用bytes.Buffer可以高效进行字符串拼接,避免不必要的内存分配。2)bytes.Equal函数用于快速比较字节切片。3)bytes.Index、bytes.Split和bytes.ReplaceAll函数可用于搜索和操作字节切片,但需注意性能问题。

字节包提供了多种功能来高效处理字节切片。1)使用bytes.Contains检查字节序列。2)用bytes.Split分割字节切片。3)通过bytes.Replace替换字节序列。4)用bytes.Join连接多个字节切片。5)利用bytes.Buffer构建数据。6)结合bytes.Map进行错误处理和数据验证。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

PhpStorm Mac 版本
最新(2018.2.1 )专业的PHP集成开发工具

适用于 Eclipse 的 SAP NetWeaver 服务器适配器
将Eclipse与SAP NetWeaver应用服务器集成。

禅工作室 13.0.1
功能强大的PHP集成开发环境

WebStorm Mac版
好用的JavaScript开发工具

SublimeText3汉化版
中文版,非常好用