รับโครงสร้างจาก C ถึง Golang

c.h

typedef signed int VarInt32;

typedef struct {
    VarInt32   VI32
} VAR_A, *VAR_B

int Add(VAR_B v_b) //the argument is a pointer

var mvar unsafe.Pointer

C.Add((*C.VAR_B)(&mvar))

fmt.Println(mvar)

รับผลลัพธ์ดังนี้:

warning: passing argument 1 of ‘add’ from incompatible pointer type [enabled by default]
note: expected ‘MVAR’ but argument is of type ‘struct <anonymous> *’

ดูเหมือนไม่ถูกต้อง

ฉันกำลังมองหาสิ่งนี้ใน golang: mvar.VI32

ขอบคุณ


ปวดหัวมาก ไม่เก่ง C/C++

นี่คือฉากของฉันเพื่อเรียก SDK (พร้อม .so libs)

c.h

typedef char*   MPChar;
typedef MLong   MRESULT;

typedef struct{
    MPChar startTime;       
    MPChar endTime;         
    MPChar platform;        
    MPChar sdkType;         
    MPChar appId;           
    MPChar sdkKey;          
    MPChar sdkVersion;      
    MPChar fileVersion;     
}ASF_ActiveFileInfo, *LPASF_ActiveFileInfo;


MRESULT ASFGetActiveFileInfo(
    LPASF_ActiveFileInfo  activeFileInfo 
);

ฉันพยายามเรียกใช้ฟังก์ชัน ASFGetActiveFileInfo ใน golang เช่นนี้:

var c_afInfo C.ASF_ActiveFileInfo

C.ASFGetActiveFileInfo(&c_afInfo)

//get the same error
//C.ASFGetActiveFileInfo((C.LPASF_ActiveFileInfo)(unsafe.Pointer(&c_afInfo)))

รับข้อผิดพลาดนี้:

# command-line-arguments
cgo-gcc-prolog: In function ‘_cgo_8c613494cf5f_Cfunc_ASFGetActiveFileInfo’:
cgo-gcc-prolog:52:2: warning: passing argument 1 of ‘ASFGetActiveFileInfo’ from incompatible pointer type [enabled by default]
In file included from ./main.go:7:0:
./inc/arcsoft_face_sdk.h:104:9: note: expected ‘LPASF_ActiveFileInfo’ but argument is of type ‘struct <anonymous> *’
 MRESULT ASFGetActiveFileInfo(
         ^
# command-line-arguments
./main.go:134:139: cannot use _cgo0 (type *_Ctype_LPASF_ActiveFileInfo) as type *_Ctype_struct___0 in argument to _Cfunc_ASFGetActiveFileInfo

พยายาม:

var c_afInfo C.LPASF_ActiveFileInfo

C.ASFGetActiveFileInfo((C.LPASF_ActiveFileInfo)&c_afInfo)

รับข้อผิดพลาดนี้

# command-line-arguments
cgo-gcc-prolog: In function ‘_cgo_061c0167bf6c_Cfunc_ASFGetActiveFileInfo’:
cgo-gcc-prolog:52:2: warning: passing argument 1 of ‘ASFGetActiveFileInfo’ from incompatible pointer type [enabled by default]
In file included from ./main.go:7:0:
./inc/arcsoft_face_sdk.h:104:9: note: expected ‘LPASF_ActiveFileInfo’ but argument is of type ‘struct <anonymous> *’
 MRESULT ASFGetActiveFileInfo(
         ^
# command-line-arguments
./main.go:134:25: type _Ctype_LPASF_ActiveFileInfo is not an expression

มีวิธีแก้ไขปัญหานี้หรือไม่?


ขอบคุณสำหรับคำตอบของ @peterSO มันใช้งานได้ แต่ยังคงแสดงข้อผิดพลาด:

cgo-gcc-prolog: In function ‘_cgo_73061f0a5639_Cfunc_ASFGetActiveFileInfo’:
cgo-gcc-prolog:98:2: warning: passing argument 1 of ‘ASFGetActiveFileInfo’ from incompatible pointer type [enabled by default]
In file included from ./main.go:7:0:
./inc/arcsoft_face_sdk.h:104:9: note: expected ‘LPASF_ActiveFileInfo’ but argument is of type ‘struct <anonymous> *’
 MRESULT ASFGetActiveFileInfo(
         ^
0 linux


ความจริงอยู่ใกล้มาก


สาธิต:https://github.com/JoeZing/stackdemo


person Joe    schedule 16.12.2019    source แหล่งที่มา
comment
อย่าใช้ประเภท struct ที่ไม่ระบุชื่อใน C: แทน typedef struct /*anonymous*/ { ... } typename_list ให้ใช้ struct struct_name { ... } เสมอ (Typedefs ใน C ค่อนข้างจะใช้งานไม่ได้ และฉันขอแนะนำให้หลีกเลี่ยงมัน แต่ก็สามารถใช้ได้หากคุณชอบมันจริงๆ การมีอยู่หรือไม่มี typedef ที่นี่ไม่เกี่ยวข้องกันจริงๆ สิ่งสำคัญคือการใช้แท็ก struct)   -  person torek    schedule 16.12.2019
comment
Typedefs ใน C นั้นเสียหายยังไงล่ะ? นั่นเป็นข้อเรียกร้องที่ไม่มีมูลความจริง   -  person Qix - MONICA WAS MISTREATED    schedule 17.12.2019


คำตอบ (1)


Go ไม่ตรงกับกฎ C typedef ที่ลึกซึ้งทั้งหมดใน cgo ง่าย ๆ เข้าไว้.


จากตัวอย่างแท็ก no struct ต่อไปนี้คือบางวิธีที่คุณสามารถส่งผ่านตัวแปร C struct และอาร์กิวเมนต์ตัวชี้จากไปที่ฟังก์ชัน C Add ไม่ปลอดภัย โดยข้ามการตรวจสอบทั้ง Go และ C (คอมไพเลอร์ GCC C)

package main

/*
// GNU Compiler Collection (GCC): Warning Options
// https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#Warning-Options
#cgo CFLAGS: -Wno-incompatible-pointer-types

typedef signed int i32_t;

// anonymous (no tag) struct
typedef struct {
    i32_t i;
} sv_t, *sp_t;

int Add(sv_t v, sp_t p);

int Add(sv_t v, sp_t p) {
    int sum = v.i;
    if (p) {
        sum += p->i;
    }
    return sum;
}
*/
import "C"

import (
    "fmt"
    "unsafe"
)

func main() {
    var svar C.sv_t
    svar.i = 42
    fmt.Printf("svar: %v  svar.i: %v\n", svar, svar.i)

    var sptr C.sp_t
    sptr = (C.sp_t)(unsafe.Pointer(new(C.sv_t)))
    sptr.i = 39
    fmt.Printf("sptr: %v  sptr.i: %v\n", sptr, sptr.i)

    sum := C.Add(svar, sptr)
    fmt.Print("Add(", svar.i, ", ", sptr.i, ") = ", sum, "\n")

    fmt.Printf("svar: %T\nsptr: %T\n", svar, sptr)
}

/*

เอาท์พุท:

$ go run so.go
svar: {42}  svar.i: 42
sptr: &{39}  sptr.i: 39
Add(42, 39) = 81
svar: main._Ctype_struct___0
sptr: main._Ctype_sp_t
$ 

สำหรับตัวอย่างเฉพาะของคุณ อาจมีลักษณะดังนี้:

package main

/*
// GNU Compiler Collection (GCC): Warning Options
// https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#Warning-Options
#cgo CFLAGS: -Wno-incompatible-pointer-types

typedef long    MLong;
typedef char*   MPChar;
typedef MLong   MRESULT;

typedef struct {
    MPChar startTime;
    MPChar endTime;
    MPChar platform;
    MPChar sdkType;
    MPChar appId;
    MPChar sdkKey;
    MPChar sdkVersion;
    MPChar fileVersion;
} ASF_ActiveFileInfo, *LPASF_ActiveFileInfo;


MRESULT ASFGetActiveFileInfo(
    LPASF_ActiveFileInfo  activeFileInfo
);

MRESULT ASFGetActiveFileInfo(
    LPASF_ActiveFileInfo  activeFileInfo
)
{
    activeFileInfo->appId = "Go";
    return 42;
}
*/
import "C"

import (
    "fmt"
    "unsafe"
)

func main() {
    asfPtr := (C.LPASF_ActiveFileInfo)(unsafe.Pointer(new(C.ASF_ActiveFileInfo)))
    r := C.ASFGetActiveFileInfo(asfPtr)
    fmt.Println(r, C.GoString(asfPtr.appId))
}

เอาท์พุท:

$ go run so.go
42 Go
$ 

จากตัวอย่างของคุณ (ที่มีแท็ก struct) ต่อไปนี้เป็นวิธีการต่างๆ ที่คุณสามารถส่งผ่านอาร์กิวเมนต์ C struct จากไปที่ฟังก์ชัน C Add: ตัวแปร ตัวชี้ และตัวชี้ที่ไม่ปลอดภัย ใน Go เราชอบประเภทที่ปลอดภัย

package main

/*
typedef signed int i32_t;

typedef struct s_t {
    i32_t i;
} sv_t, *sp_t;

int Add(sv_t v, sp_t p);

int Add(sv_t v, sp_t p) {
    int sum = v.i;
    if (p) {
        sum += p->i;
    }
    return sum;
}
*/
import "C"

import (
    "fmt"
    "unsafe"
)

func main() {
    svar := C.struct_s_t{i: 42}

    sptr := &C.struct_s_t{i: 39}
    sum := C.Add(svar, sptr)
    fmt.Print("Add(", svar.i, ", ", sptr.i, ") = ", sum, "\n")

    uptr := unsafe.Pointer(&C.struct_s_t{i: 7})
    sum = C.Add(svar, (C.sp_t)(uptr))
    fmt.Print("Add(", svar.i, ", ", (C.sp_t)(uptr).i, ") = ", sum, "\n")
    sum = C.Add(svar, (*C.struct_s_t)(uptr))
    fmt.Print("Add(", svar.i, ", ", (*C.struct_s_t)(uptr).i, ") = ", sum, "\n")

    fmt.Printf("svar: %T\nsptr: %T\nuptr: %T\n", svar, sptr, uptr)
}

เอาท์พุท:

$ go run so.go
Add(42, 39) = 81
Add(42, 7) = 49
Add(42, 7) = 49
svar: main._Ctype_struct_s_t
sptr: *main._Ctype_struct_s_t
uptr: unsafe.Pointer
$
person peterSO    schedule 16.12.2019
comment
ฉันอัปเดตคำถาม คุณช่วยฉันหน่อยได้ไหม? ขอบคุณ :) - person Joe; 17.12.2019
comment
@Joe: ฉันอัปเดตคำตอบของฉัน ดูสองตัวอย่างแรก - person peterSO; 17.12.2019
comment
น่าทึ่งมาก มันใช้งานได้ แต่ยังคงมีข้อผิดพลาดเหมือนกับคำถาม: arcsoft_face_sdk.h:104:9: note: คาดว่า 'LPASF_ActiveFileInfo' แต่อาร์กิวเมนต์เป็นประเภท 'struct ‹anonymous› * - person Joe; 18.12.2019
comment
@Joe: คุณเรียกใช้คำตอบของฉันกับโค้ดตัวอย่าง ASFGetActiveFileInfo ที่โพสต์ของคุณหรือไม่ ผลลัพธ์ของคุณคืออะไร? บรรทัด #cgo CFLAGS: -Wno-incompatible-pointer-types ระงับข้อความเตือน 'struct ‹anonymous› *' ของคอมไพเลอร์ GCC C ที่คาดหวัง ในโค้ดตัวอย่างที่ไม่ได้โพสต์ของคุณ คุณทำตามตัวอย่างของฉันและใส่บรรทัด #cgo CFLAGS: -Wno-incompatible-pointer-types หรือไม่ โพสต์โค้ดเพื่อดูตัวอย่างที่สร้างข้อความแสดงข้อผิดพลาดของคุณ ดูวิธีสร้างตัวอย่างขั้นต่ำที่สามารถทำซ้ำได้ หากไม่มีสิ่งนั้นเราก็เดาได้เท่านั้น - person peterSO; 18.12.2019
comment
ขอบคุณ ฉันอัปเดตคำถามเพิ่มการสาธิตใน github: github.com/JoeZing/stackdemo - person Joe; 18.12.2019