Python 访问golang中的C数组

Python 访问golang中的C数组,python,go,ctypes,Python,Go,Ctypes,我有两个文件,module.go和test.py。我的目标是加速一些用python完成的计算,但在访问go中的整数数组时会遇到问题 module.go package main import "C" //export Example func Example(testArray []C.int) C.int { return testArray[2] } func main() {} 以及python中的简单测试文件: from ctypes import * # Load c

我有两个文件,
module.go
test.py
。我的目标是加速一些用python完成的计算,但在访问go中的整数数组时会遇到问题

module.go

package main

import "C"

//export Example
func Example(testArray []C.int) C.int {
    return testArray[2]
}

func main() {}
以及python中的简单测试文件:

from ctypes import *

# Load compiled go module
lib = cdll.LoadLibrary("./gomodule.so")
# We are passing an array of 256 elements and recieving integer
lib.Example.argtypes = [c_int * 256]
lib.Example.restype = c_int
pyarr = [x for x in range(256)]
# Make C array from py array
arr = (c_int * len(pyarr))(*pyarr)
print lib.Example(arr)
使用
go build-buildmode=c-shared-o gomodule.so module.go编译go模块后,启动python文件,我得到:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x12 pc=0x7fb18b6e688c]

goroutine 17 [running, locked to thread]:
main.Example(...)
        /home/metro/go/src/github.com/golubaca/carinago/module.go:7
main._cgoexpwrap_53c1c00d0ad3_Example(0xa, 0x7fff33a2eac0, 0x7fff33a2ea70, 0x722a921de6cae100)
        _cgo_gotypes.go:47 +0x1c
Aborted (core dumped)

我知道C数组与Go不同,但是找不到任何教程如何在不惊慌的情况下访问它的值。

C中的数组不能自动转换为Go中的切片。请注意,在Go中,切片有两部分:长度和指向备份数据的指针

因此,您必须从指针手动创建切片

package main

import (
    "C"
    "reflect"
    "unsafe"
)

//export Example
func Example(carr *C.int, size int, idx int) C.int {

    // Build the slice manually using unsafe
    var slice []C.int
    header := (*reflect.SliceHeader)(unsafe.Pointer(&slice))
    header.Cap = size
    header.Len = size
    header.Data = uintptr(unsafe.Pointer(carr))

    return slice[idx]
}

func main() {}
然后在python代码中调用Go exported函数,如下所示:

from ctypes import *

# Load compiled go module
lib = cdll.LoadLibrary("./gomodule.so")
# We are passing an array of 256 elements and recieving integer
lib.Example.argtypes = [c_int * 256]
lib.Example.restype = c_int
pyarr = [x for x in range(256)]
# Make C array from py array
arr = (c_int * len(pyarr))(*pyarr)
print lib.Example(arr, len(arr), 4)

上面的示例应该打印数组的第四个索引元素

这是惯用的、高效的Go解决方案(避免反射)

module.go

package main

import "C"

import "unsafe"

//export Example
func Example(cArray *C.int, cSize C.int, i C.int) C.int {
    gSlice := (*[1 << 30]C.int)(unsafe.Pointer(cArray))[:cSize:cSize]
    return gSlice[i]
}

func main() {}
输出:

$ go build -buildmode=c-shared -o gomodule.so module.go
$ python test.py
4
$ 

作为建议,你看过numpy吗?(我公开承认我不知道这段代码中发生了什么。但是,“整数数组”的计算听起来像是numpy部门。它在加速计算方面帮了我很多)是的,我有,但我想使用go,因为我已经有了一些其他代码,我想将许可证签入作为
文件进行集成,所以
文件,因为它至少比普通python文件或pyc更难逆转engeneer。所以这里的主要思想是在go中对关键代码部分使用许可证检查,并一起编译。这是正确的答案。我没有想到头,但现在我知道了寻找其他类型的头。谢谢!很好,我尝试了这个,结果与第一个答案相同,但共享对象的文件大小更小,这很好。我必须接受这个“被接受”的答案,因为转换效率很高。非常感谢你们两位。
[1@Nathan.:Go数组必须有一个声明的大小。这设置了片的最大允许大小和容量。Go将根据参数构造实际的片头,并使用数组的基作为基础数组。因此,如果数组中实际有256
C.int
s,则片将以此作为其长度和容量Go无法访问实际阵列之外的区域。
$ go build -buildmode=c-shared -o gomodule.so module.go
$ python test.py
4
$