是否可以编写修改Go代码中定义的类型结构的C函数?

时间:2014-08-29 08:30:01

标签: c struct go cgo

这是this question的后续行动。我在那里假设可能不是真的,这就是我明确询问它的原因。因为我忘了询问这是否真的可行,我已经就此提出了issue #8114


使用cgo,Go代码可以在C类型上运行,如下所示:

package foo

//#include <sys/stat.h>
import "C"

func fileSizeFromStat(stat *C.struct_stat) int64 {
    return int64(stat.st_size)
}

反过来可能吗?即编写在go类型上运行的C函数?上述问题概述了具体内容;我想编组无法从Go代码访问的C结构,因为它们使用了联合或位域,或者因为它们的对齐使它们与Go代码不兼容。

2 个答案:

答案 0 :(得分:1)

据我所知,不,你不能。

但是你可以使用像https://github.com/OneOfOne/go-nfqueue/blob/master/nfqueue.go#L130这样丑陋的东西,你可以导出一个Go函数,它需要很多指针并在go中构造你的Go结构。

答案 1 :(得分:1)

我编写了以下肮脏的黑客来解决明显无法从C访问Go结构。虽然这个hack不能保证工作,但它适用于Go和C同意如何布局结构的情况对我感兴趣的所有案件都是如此。

对于我想要访问的每个Go结构

type JewelTarget struct {
    SensRes [2]byte
    Id      [4]byte
    Baud    int
}

我创建了一个相应的C结构,它具有相同宽度的字段,并且希望具有相同的布局:

typedef ptrdiff_t GoInt;

struct JewelTarget {
    uint8_t SensRes[2];
    uint8_t Id[4];
    GoInt   Baud;
};

然后我编写使用这些C结构的C函数:

extern void
marshallJewelTarget(nfc_target *nt, const struct JewelTarget *jt)
{
    nfc_jewel_info *ji = &nt->nti.nji;

    memcpy(ji->btSensRes, jt->SensRes, sizeof(jt->SensRes));
    memcpy(ji->btId, jt->Id, sizeof(jt->Id));

    nt->nm.nbr = jt->Baud;
    nt->nm.nmt = NMT_JEWEL;
}

并将它们称为参数具有相应的Go类型:

func (d *JewelTarget) Marshall() uintptr {
    nt := mallocTarget()
    jt := (*C.struct_JewelTarget)(unsafe.Pointer(d))

    C.marshallJewelTarget(nt, jt)

    return uintptr(unsafe.Pointer(nt))
}

所有示例均来自我的nfc bindings