Golang中使用CGO进行结构体传递的方法

Golang中使用CGO进行结构体传递的方法 存在一个C结构体如下:

struct dcmi_chip_info {
unsigned char chip_type[MAX_CHIP_NAME_LEN];
unsigned char chip_name[MAX_CHIP_NAME_LEN];
unsigned char chip_ver[MAX_CHIP_NAME_LEN];
unsigned int aicore_cnt;
};

以及一个C函数如下: DCMIDLLEXPORT int dcmi_get_device_chip_info(int card_id, int device_id, struct dcmi_chip_info *chip_info);

然后我想使用CGO来获取结果:

ret = C.dcmi_get_device_id_in_card(card_id_list[card_id_index],
(*C.int)(unsafe.Pointer(&device_id_max)),
(*C.int)(unsafe.Pointer(&mcu_id)),
(*C.int)(unsafe.Pointer(&cpu_id)))
/*chip_info := C.struct_dcmi_chip_info{
chip_type: [C.MAX_CHIP_NAME_LEN]C.uchar{},
chip_name: [C.MAX_CHIP_NAME_LEN]C.uchar{},
chip_ver:  [C.MAX_CHIP_NAME_LEN]C.uchar{},
}*/
chip_info := C.struct_dcmi_chip_info{}
ret = C.dcmi_get_device_chip_info(card_id_list[card_id_index], (C.int)(device_id_max), &chip_info)
fmt.Printf("%T\n", chip_info.chip_name)
fmt.Println("chip_type", chip_info.chip_name)

但我得到的结果是: 图片

如何才能正确地进行传递?非常感谢。


更多关于Golang中使用CGO进行结构体传递的方法的实战教程也可以访问 https://www.itying.com/category-94-b0.html

5 回复

这对我真的很有用。非常感谢。

更多关于Golang中使用CGO进行结构体传递的方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


谢谢,但错误是:

cannot use &chip_info.chip_name[0] (value of type *_Ctype_uchar) as *_Ctype_char value in argument to (_Cfunc_GoString)

这看起来像是一个以空字符结尾的字符串,内容是“MCU”。因此,你可能需要将

fmt.Println(“chip_type”, chip_info.chip_name)

替换为

fmt.Println(“chip_type”, C.GoString(&chip_info.chip_name[0]))

抱歉。*C.uchar 需要转换为 *C.char,因为 C.GoString 需要的是后者。Go 编译器不允许像 (*C.char)(&chip_info.chip_name[0]) 这样直接进行转换。

然而,任何指针类型都可以转换为 unsafe.Pointer,而 unsafe.Pointer 又可以转换为任何指针类型。

fmt.Println(C.GoString((*C.char)(unsafe.Pointer(&chip_info.chip_name[0]))))

括号太多了。分解开来,可以这样写。

chipNameUCharPointer := &chip_info.chip_name[0]
chipNameUnsafePointer := unsafe.Pointer(chipNameUCharPointer)
chipNameCharPointer := (*C.char)(chipNameUnsafePointer)
chipNameGoString := C.GoString(chipNameCharPointer)
fmt.Println(chipNameGoString)

在Go中通过CGO传递C结构体时,需要正确处理内存对齐和类型转换。以下是正确的实现方法:

package main

/*
#include <string.h>
#define MAX_CHIP_NAME_LEN 32

struct dcmi_chip_info {
    unsigned char chip_type[MAX_CHIP_NAME_LEN];
    unsigned char chip_name[MAX_CHIP_NAME_LEN];
    unsigned char chip_ver[MAX_CHIP_NAME_LEN];
    unsigned int aicore_cnt;
};

DCMIDLLEXPORT int dcmi_get_device_chip_info(int card_id, int device_id, struct dcmi_chip_info *chip_info);
*/
import "C"
import (
    "fmt"
    "unsafe"
)

func main() {
    var card_id C.int = 0
    var device_id C.int = 0
    
    // 创建C结构体实例
    var chip_info C.struct_dcmi_chip_info
    
    // 调用C函数
    ret := C.dcmi_get_device_chip_info(card_id, device_id, &chip_info)
    
    if ret != 0 {
        fmt.Printf("Error: %d\n", ret)
        return
    }
    
    // 正确转换C字符串到Go字符串
    chipType := C.GoString((*C.char)(unsafe.Pointer(&chip_info.chip_type[0])))
    chipName := C.GoString((*C.char)(unsafe.Pointer(&chip_info.chip_name[0])))
    chipVer := C.GoString((*C.char)(unsafe.Pointer(&chip_info.chip_ver[0])))
    
    fmt.Printf("Chip Type: %s\n", chipType)
    fmt.Printf("Chip Name: %s\n", chipName)
    fmt.Printf("Chip Version: %s\n", chipVer)
    fmt.Printf("AI Core Count: %d\n", chip_info.aicore_cnt)
}

如果C函数返回的字符串可能包含空字符,使用以下方法:

// 使用C.GoStringN处理可能包含空字符的字符串
chipType := C.GoStringN((*C.char)(unsafe.Pointer(&chip_info.chip_type[0])), C.MAX_CHIP_NAME_LEN)
chipName := C.GoStringN((*C.char)(unsafe.Pointer(&chip_info.chip_name[0])), C.MAX_CHIP_NAME_LEN)
chipVer := C.GoStringN((*C.char)(unsafe.Pointer(&chip_info.chip_ver[0])), C.MAX_CHIP_NAME_LEN)

// 去除尾部空字符
chipType = strings.TrimRight(chipType, "\x00")
chipName = strings.TrimRight(chipName, "\x00")
chipVer = strings.TrimRight(chipVer, "\x00")

对于需要预先分配内存的情况:

// 方法1:直接声明结构体变量
var chipInfo C.struct_dcmi_chip_info

// 方法2:使用new创建指针
chipInfoPtr := new(C.struct_dcmi_chip_info)
ret := C.dcmi_get_device_chip_info(card_id, device_id, chipInfoPtr)

// 方法3:使用malloc分配内存(需要手动释放)
chipInfoPtr := (*C.struct_dcmi_chip_info)(C.malloc(C.sizeof_struct_dcmi_chip_info))
defer C.free(unsafe.Pointer(chipInfoPtr))

// 清零内存
C.memset(unsafe.Pointer(chipInfoPtr), 0, C.sizeof_struct_dcmi_chip_info)

如果需要在Go中定义对应的结构体类型:

type ChipInfo struct {
    ChipType   [C.MAX_CHIP_NAME_LEN]byte
    ChipName   [C.MAX_CHIP_NAME_LEN]byte
    ChipVer    [C.MAX_CHIP_NAME_LEN]byte
    AICoreCnt  uint32
}

// 将C结构体转换为Go结构体
func convertToGoStruct(cInfo *C.struct_dcmi_chip_info) ChipInfo {
    var goInfo ChipInfo
    
    // 复制字节数组
    copy(goInfo.ChipType[:], C.GoBytes(unsafe.Pointer(&cInfo.chip_type[0]), C.MAX_CHIP_NAME_LEN))
    copy(goInfo.ChipName[:], C.GoBytes(unsafe.Pointer(&cInfo.chip_name[0]), C.MAX_CHIP_NAME_LEN))
    copy(goInfo.ChipVer[:], C.GoBytes(unsafe.Pointer(&cInfo.chip_ver[0]), C.MAX_CHIP_NAME_LEN))
    
    goInfo.AICoreCnt = uint32(cInfo.aicore_cnt)
    return goInfo
}

确保在调用C函数前正确初始化参数,并使用正确的类型转换。问题中图片显示的输出异常通常是由于没有正确处理C字符串到Go字符串的转换导致的。

回到顶部