3

C 構造体へのポインターをパラメーターとして受け取る C 関数のラッパーを作成したいと考えています。

私の Go コードでは、C 構造体にスペースを割り当てるために 2 つの方法を試しました。

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) の方法で *C.struct_T32_Breakpoint の代わりに *[0]byte の型が作成され、*C.struct_T32_Breakpoint へのキャストが機能しないようです。

方法 (1) と (2) の使用の違いは何ですか?

ありがとう。

テストコード

ファイル: t32.h

#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__ */

ファイル: remote.c

#include "t32.h"

int T32_GetBreakpointList (int* numbps, T32_Breakpoint* bps, int max)
{ 
    return 0;
}

ファイル : t32.go

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
}
4

1 に答える 1

2

2番目のスニペットがコンパイルされない理由は2つあります。

1つ目は、大文字と小文字が一致しないことです。C宣言はstructt32_breakpointを宣言しますが、GoコードはstructT32_Breakpointを参照します。Cでは大文字と小文字が区別されますが、定義されていない構造体へのポインターを作成できます。それがCGoがあなたがしていると考えていることです。構造体の内容とサイズが不明なため、このポインターを逆参照することはできません。これは基本的にvoidポインターと同等ですが、より強力な型指定があります。Cgoはそれをvoidポインターとして扱い、* [0]バイト、つまりゼロサイズのオブジェクトへのポインターとして変換します。ただし、Cとは異なり、Goでは、ポインターを受け取る関数にvoidポインターを渡すことはできません。したがって、タイプの不一致があります。

もう1つの問題は、T32_Breakpoint*の代わりにstructt32_breakpoint *を渡す場合、Cで関数宣言を変更する必要があることです。2つのタイプの違いはおそらくCでは重要ではありませんが、Goでは重要です。 GoはCよりもタイピングが強いので。

于 2013-01-24T20:17:35.400 に答える