kaisawind's blog
  • 关于
  • 所有帖子

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)))


辽ICP备2021007608号 | © 2025 | kaisawind

Facebook Twitter GitHub