cgo中go结构体与void*的转换 - Sat, Oct 24, 2020
cgo中go结构体与void*的转换
1. 概述
C语言中入参大部分情况下是void类型的指针,需要转换成go语言相应的类型。 go语言相应的结构体,也需要转换成C语言的void指针。
2. 实现
有如下C结构体定义 HCNetSDK.h
typedef unsigned short WORD;
typedef unsigned char BYTE;
#define ACS_CARD_NO_LEN 32 //门禁卡号长度
typedef struct tagNET_DVR_CARD_CFG_SEND_DATA
{
DWORD dwSize;
BYTE byCardNo[ACS_CARD_NO_LEN]; //卡号
DWORD dwCardUserId; //持卡人ID
BYTE byRes[12];
}NET_DVR_CARD_CFG_SEND_DATA, *LPNET_DVR_CARD_CFG_SEND_DATA;
定义成如下go结构体 byRes是占位符,所以在go中是不关心大小的,所以定义成了切片。 defination.go
// CardCfgSendData 获取卡参数的发送数据
type CardCfgSendData struct {
Size uint32
CardNo string //卡号 ACS_CARD_NO_LEN
CardUserId uint32 //持卡人ID
byRes []byte //size12
}
结构体转换函数
注意1: C的宏定义转go的全局变量
注意2: C的char数组转go的string,最后会有一个0x00
的结束符是go不需要的。
注意2:由于go无法使用类型计算结构体大小,所以计算结构体大小时需要先创建变量。
convert.go
AcsCardNoLen = C.ACS_CARD_NO_LEN // 32 //门禁卡号长度
// GoCCardCfgSendData Go to C
func GoCCardCfgSendData(in *CardCfgSendData) (out C.LPNET_DVR_CARD_CFG_SEND_DATA) {
cardNo := [AcsCardNoLen]C.BYTE{}
for i := 0; i < len(in.CardNo) && i < AcsCardNoLen-1; i++ {
cardNo[i] = C.BYTE(in.CardNo[i])
}
var temp C.NET_DVR_CARD_CFG_SEND_DATA
size := uint32(unsafe.Sizeof(temp)) // 单纯计算size, 无法使用类型计算
out = &C.NET_DVR_CARD_CFG_SEND_DATA{
dwSize: C.DWORD(size),
byCardNo: cardNo,
dwCardUserId: C.DWORD(in.CardUserId),
}
return
}
万事具备,最后是C结构体指针转C的void指针
使用unsafe.Pointer
转换为go中无符号指针,再通过C.LPVOID
进行强转。
lpInBuffer = C.LPVOID(unsafe.Pointer(GoCCardCfgSendData(value)))