Golang中如何将`[]uchar`转换为`[]byte`

Golang中如何将[]uchar转换为[]byte 首先,cgo 确实非常棒,感谢你们提供了这个工具。 🙂

不过,我确实有一个问题。我有很多 C 结构体,它们只包含一个字节数组,我想将其中的数组作为 []byte 来使用。例如:

typedef struct {
    unsigned char data[64];
} pubkey;

我希望能够这样做:

type SchnorrPublicKey struct {
	pubkey C.pubkey
}

func (key *SchnorrPublicKey) String() string {
	return hex.EncodeToString(key.pubkey.data[:])
}

但我遇到了以下错误: ./schnorr.go:39:43: cannot use key.pubkey.data[:] (type []_Ctype_uchar) as type []byte in argument to hex.EncodeToString

我可以通过类似以下的方式使其工作: return hex.EncodeToString(C.GoBytes(unsafe.Pointer(&key.pubkey.data[0]), C.int(len(key.pubkey.data))))

但这感觉有点笨拙。仅仅为了将 _Ctype_uchar 类型替换为 byte 类型,就把一个已经是 Go 切片的东西转换成另一个 Go 切片,这引入了很多不必要的复杂性,而且它们本来就是 100% 兼容的。

有没有更好的方法来实现这个?


更多关于Golang中如何将`[]uchar`转换为`[]byte`的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

你好,@elichai,可以尝试通过 unsafe.Pointer 进行类型转换:

type SchnorrPublicKey struct {
	pubkey C.pubkey
}

func (key *SchnorrPublicKey) String() string {
    pk := *((*[64]byte)(unsafe.Pointer(&key.pubkey)))
    return hex.EncodeToString(pk[:])
}

更多关于Golang中如何将`[]uchar`转换为`[]byte`的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go中,_Ctype_ucharbyte确实是完全兼容的类型,但Go的类型系统将它们视为不同的类型。以下是几种更简洁的转换方法:

方法1:使用unsafe直接转换(推荐)

func (key *SchnorrPublicKey) String() string {
    // 将[]_Ctype_uchar直接转换为[]byte
    cslice := key.pubkey.data[:]
    return hex.EncodeToString(*(*[]byte)(unsafe.Pointer(&cslice)))
}

方法2:使用切片头转换

func (key *SchnorrPublicKey) String() string {
    cslice := key.pubkey.data[:]
    
    // 使用unsafe.Pointer和切片头进行转换
    var result []byte
    sh := (*reflect.SliceHeader)(unsafe.Pointer(&result))
    csh := (*reflect.SliceHeader)(unsafe.Pointer(&cslice))
    sh.Data = csh.Data
    sh.Len = csh.Len
    sh.Cap = csh.Cap
    
    return hex.EncodeToString(result)
}

方法3:使用类型转换辅助函数

func ucharSliceToByteSlice(cslice []_Ctype_uchar) []byte {
    return *(*[]byte)(unsafe.Pointer(&cslice))
}

func (key *SchnorrPublicKey) String() string {
    return hex.EncodeToString(ucharSliceToByteSlice(key.pubkey.data[:]))
}

方法4:直接使用unsafe.Pointer(最简洁)

func (key *SchnorrPublicKey) String() string {
    // 直接获取底层数组的指针并转换为byte切片
    ptr := unsafe.Pointer(&key.pubkey.data[0])
    return hex.EncodeToString((*[64]byte)(ptr)[:])
}

完整示例

package main

/*
#include <stdint.h>

typedef struct {
    unsigned char data[64];
} pubkey;
*/
import "C"
import (
    "encoding/hex"
    "unsafe"
)

type SchnorrPublicKey struct {
    pubkey C.pubkey
}

func (key *SchnorrPublicKey) String() string {
    // 方法1的示例
    cslice := key.pubkey.data[:]
    return hex.EncodeToString(*(*[]byte)(unsafe.Pointer(&cslice)))
}

// 或者使用方法4
func (key *SchnorrPublicKey) String2() string {
    ptr := unsafe.Pointer(&key.pubkey.data[0])
    return hex.EncodeToString((*[64]byte)(ptr)[:])
}

方法1是最直接的方式,它利用了[]_Ctype_uchar[]byte具有相同内存布局的特性,通过unsafe.Pointer进行直接类型转换,避免了额外的内存分配和复制操作。

回到顶部