cgo中go结构体与void*的转换

  1. 1. 概述
  2. 2. 实现

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

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 wind.kaisa@gmail.com

💰

×

Help us with donation