【问题标题】:how to copy C.int address into C.char in cgo?如何在cgo中将C.int地址复制到C.char中?
【发布时间】:2021-07-03 20:00:06
【问题描述】:

使用 cgo 我正在调用 c 函数。我遇到了必须将 C.int 地址复制到 C.char[4] 的情况。我可以这样做吗?

code sn-p C-结构:

struct data
{
    char    *a_add; 
    unsigned int length;
}

转码

func main() {
     var d[3] C.data
     var filedescriptor C.int
     d[0].a_add = &filedescriptor 
     d[0].length = 4
}

问题是 a_add 是一个 char*。但我需要传递 int 变量地址。 c 代码是遗留代码,我现在无法修复数据类型。其他 C 模块使用它,并且它在 C 中工作并带有警告。在哪里,它是错误的。

有什么方法可以将 int 变量的地址复制到 cgo 中的 char* 数组中。

更新: 我试过 d[0].a_add = (*C.char)(unsafe.Pointer(&filedescriptor )),

出现错误: 恐慌:运行时错误:cgo 参数的 Go 指针指向 Go 指针

我错过了什么?

【问题讨论】:

  • 您阅读过golang.org/pkg/unsafe/#Pointer 的文档吗?
  • 在查看给定站点后更新了原始帖子
  • 你试过(*C.char)(&filedescriptor)。抱歉,我对 cgo 不熟悉,但这是我的最佳猜测

标签: c go cgo


【解决方案1】:

您遇到的一个问题是,在调用 C 代码时,您可能不会将指针传递给 Go 指针。变量filedescriptorC.int,但&filedescriptor 是Go 指针,因此您不能使用它(或者更确切地说,您不能在a_add 字段中使用它 作为值) .

您的 C 代码有很多我不清楚的地方,但您可能可以使用下面的代码。请注意,对于您的特定情况,此代码可能是多余的。它并不意味着特别高效或好,只是尽可能清晰同时非常灵活——例如,它可以读取和写入打包的 C 结构。

package main

// #include <stdio.h>
// #include <stdlib.h>
// #include <string.h>
//
// struct data {
//     char *a_add;
//     unsigned int length;
// };
//
// void f(struct data *p) {
//    printf("p->a_add = %p, p->length = %u\n", p->a_add, p->length);
//    printf("p->a_add as an int: %d\n", *(int *)p->a_add);
//    *(int *)p->a_add = 0x12345678;
// }
import "C"

import (
        "fmt"
        "unsafe"
)

const cIntSize = C.sizeof_int

// Produce a Go int64 from a C int.  The caller passes the address
// of the C int.
func int64FromCInt(ci unsafe.Pointer) int64 {
        // Get a slice pointing to the bytes of the C int.
        sci := (*[cIntSize]byte)(ci)[:]
        switch {
        case cIntSize == unsafe.Sizeof(int64(0)):
                var gi int64
                sgi := (*[unsafe.Sizeof(gi)]byte)(unsafe.Pointer(&gi))[:]
                copy(sgi, sci)
                return gi
        case cIntSize == unsafe.Sizeof(int32(0)):
                var gi int32
                sgi := (*[unsafe.Sizeof(gi)]byte)(unsafe.Pointer(&gi))[:]
                copy(sgi, sci)
                return int64(gi)
        case cIntSize == unsafe.Sizeof(int(0)):
                var gi int
                sgi := (*[unsafe.Sizeof(gi)]byte)(unsafe.Pointer(&gi))[:]
                copy(sgi, sci)
                return int64(gi)
        default:
                panic("no Go integer size matches C integer size")
        }
}

// Write C int (via an unsafe.Pointer) from Go int.  The caller
// passes the address of the C int.
func writeCIntFromInt(gi int, ci unsafe.Pointer) {
        // Get a slices covering the bytes of the C int.
        sci := (*[cIntSize]byte)(ci)[:]
        switch {
        case cIntSize == unsafe.Sizeof(gi):
                sgi := (*[unsafe.Sizeof(gi)]byte)(unsafe.Pointer(&gi))[:]
                copy(sci, sgi)
        case cIntSize == unsafe.Sizeof(int64(0)):
                // Copy value to int64 for copying purposes.
                // Since int64 holds all int values, this always works.
                gi2 := int64(gi)
                sgi := (*[unsafe.Sizeof(gi)]byte)(unsafe.Pointer(&gi2))[:]
                copy(sci, sgi)
        case cIntSize == unsafe.Sizeof(int32(0)):
                // Copy value to int32 for copying purposes.
                // Panic if we destroy the value via truncation.
                gi2 := int32(gi)
                if int(gi2) != gi {
                        panic(fmt.Sprintf("unable to send Go value %x to C: size of Go int=%d, size of C int=%d", gi, unsafe.Sizeof(gi), cIntSize))
                }
                sgi := (*[unsafe.Sizeof(gi)]byte)(unsafe.Pointer(&gi2))[:]
                copy(sci, sgi)
        default:
                panic("no Go integer size matches C integer size")
        }
}

func main() {
        b := C.malloc(cIntSize)
        defer C.free(b)
        writeCIntFromInt(32767, b)
        d := C.struct_data{a_add: (*C.char)(b), length: cIntSize}
        fmt.Println("calling C.f(d)")
        C.f(&d)
        result := int64FromCInt(unsafe.Pointer(d.a_add))
        fmt.Printf("result = %#x\n", result)
}

【讨论】:

    猜你喜欢
    • 2019-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-25
    • 1970-01-01
    • 2018-11-01
    • 2010-09-24
    相关资源
    最近更新 更多