我想为我的C函数创建一个包装器,它将指向C struct的指针作为参数。
在我的Go代码中,我尝试了两种方法来为C struct分配空间:
bps := make([]_Ctype_T32_Breakpoint, max) (1)
C.MyFunc((*_Ctype_T32_Breakpoint)(unsafe.Pointer(&bps[0]), C.int(max))
bps := make([]C.struct_T32_Breakpoint, max) (2)
C.MyFunc((*C.struct_T32_Breakpoint)(unsafe.Pointer(&bps[0]), C.int(max))
对于(1)方法,它可以工作,但对于(2)方法,我收到错误消息:
cannot use (*[0]byte)(unsafe.Pointer(&bps[0])) (type *[0]byte) as type *_Ctype_T32_Breakpoint in function argument
为什么方法(2)创建了* [0]字节的类型而不是* C.struct_T32_Breakpoint,并且似乎转换为* C.struct_T32_Breakpoint不起作用。
使用方法(1)和(2)有什么区别?
感谢。
#ifndef __T32_H__
#define __T32_H__
typedef unsigned char byte;
typedef unsigned short word;
typedef unsigned int dword;
typedef struct t32_breakpoint {
dword address;
byte enabled;
dword type;
dword auxtype;
} T32_Breakpoint;
int T32_GetBreakpointList( int *, T32_Breakpoint*, int );
#endif /* __T32_H__ */
#include "t32.h"
int T32_GetBreakpointList (int* numbps, T32_Breakpoint* bps, int max)
{
return 0;
}
package t32
// #cgo linux,amd64 CFLAGS: -DT32HOST_LINUX_X64
// #cgo linux,386 CFLAGS: -DT32HOST_LINUX_X86
// #cgo windows,amd64 CFLAGS: -D_WIN64
// #cgo windows,386 CFLAGS: -D_WIN32
// #cgo windows CFLAGS: -fno-stack-check -fno-stack-protector -mno-stack-arg-probe
// #cgo windows LDFLAGS: -lkernel32 -luser32 -lwsock32
// #include "t32.h"
// #include <stdlib.h>
import "C"
import (
"errors"
"unsafe"
)
const (
_INVALID_U64 = 0xFFFFFFFFFFFFFFFF
_INVALID_S64 = -1
_INVALID_U32 = 0xFFFFFFFF
_INVALID_S32 = -1
_INVALID_U16 = 0xFFFF
_INVALID_S16 = -1
_INVALID_U8 = 0xFF
_INVALID_S8 = -1
)
type BreakPoint struct {
Address uint32
Enabled int8
Type uint32
Auxtype uint32
}
func GetBreakpointList(max int) (int32, []BreakPoint, error) {
var numbps int32
// bps := make([]_Ctype_T32_Breakpoint, max) // Method (1), can compile
// code, err := C.T32_GetBreakpointList((*C.int)(&numbps), (*_Ctype_T32_Breakpoint)(unsafe.Pointer(&bps[0])), C.int(max))
bps := make([]C.struct_T32_Breakpoint, max) // Method (2) can't compile
code, err := C.T32_GetBreakpointList((*C.int)(&numbps), (*C.struct_T32_Breakpoint)(unsafe.Pointer(&bps[0])), C.int(max))
if err != nil {
return _INVALID_S32, nil, err
} else if code != 0 {
return _INVALID_S32, nil, errors.New("T32_GetBreakpointList Error")
}
if numbps > 0 {
var gbps = make([]BreakPoint, numbps)
for i := 0; i < int(numbps); i++ {
gbps[i].Address = uint32(bps[i].address)
gbps[i].Auxtype = uint32(bps[i].auxtype)
gbps[i].Enabled = int8(bps[i].enabled)
gbps[i].Type = uint32(bps[i]._type)
}
return numbps, gbps, nil
}
return 0, nil, nil
}
答案 0 :(得分:2)
第二个片段无法编译有两个原因。
首先是大写不匹配。 C声明声明了struct t32_breakpoint,但Go代码引用了struct T32_Breakpoint。 C区分大小写,但它允许创建指向尚未定义的结构的指针。这就是CGo认为你在做的事情。由于结构的内容和大小未知,因此无法取消引用此指针。它基本上等同于一个void指针,但键入更强。 Cgo将其视为void指针,将其转换为* [0]字节,即指向零大小对象的指针。但与C不同,Go不允许将void指针传递给任何带指针的函数。所以它的类型不匹配。
另一个问题是,如果你想传递一个struct t32_breakpoint *而不是一个T32_Breakpoint *,你将需要在C中更改你的函数声明。这两种类型之间的区别在C中可能并不重要,但它是在Go中,因为Go的输入比C更强。