从 **char 到 python 列表

from **char to python list

问题已经解决,请看问题下方的回答

但是我终于发现把GO函数嵌入到Python中非常愚蠢。这种嵌入失败的主要原因是Go函数很难知道什么时候回收内存资源,从而导致内存泄漏。

目前,我认为将它们结合在一起的最佳方式可能是消息通信,例如袜子。

如果我的想法有误请指正。


原问题:


在C端,一个函数returns一个字符串数组(比如["i 0","i 1","i 2","i 3"]),类型是**char.

在Python端,**char输出被读入一个变量(比如cArray),类型为POINTER(c_char_p)

我的问题:如何从 cArray 创建一个 python 列表?即获得pylist == ["i 0","i 1","i 2","i 3"]

我也想知道python里有没有取值操作,比如C里的*操作

代码示例如下:

C方(其实是Go)

package main

//#include <stdlib.h>
import "C"
import (
    "unsafe"
)

//export TestLoad
func TestLoad(cstr *C.char) **C.char {
    gostr := C.GoString(cstr)
    goslice := []string{gostr, "i 0", "i 1", "i 2", "i 3"}
    cArray := C.malloc(C.size_t(len(goslice)) * C.size_t(unsafe.Sizeof(uintptr(0))))
    defer C.free(unsafe.Pointer(cArray))
    temp := (*[1<<30 - 1]*C.char)(cArray)
    for k, v := range goslice {
        temp[k] = C.CString(v)
    }

    return (**C.char)(cArray)
}

func main() {
}

Python边

from ctypes import *

mylib = cdll.LoadLibrary("./mylib.so")
mylib.TestLoad.argtype = c_char_p
mylib.TestLoad.restype = POINTER(c_char_p)  # ***Is it possible to have two or more restypes?*** 

pystr = "hello"                             #  python str
b = pystr.encode("utf-8")                   #  convert str to bytes
resp = mylib.TestLoad(b)                    #  call CGo function, and get resp typed POINTER(c_char_p)
list_len = 5                                #  assume the length of list is known
'''
TODO
'''

顺便说一句,单个 C 或 CGO 函数 是否可以有两个或更多 returns?我试过了,编译失败。

感谢您的帮助。

解决方案:

C side (GO) -- defer C.free...所在的那行要注释掉

package main

//#include <stdlib.h>
import "C"
import (
    "fmt"
    "unsafe"
)

//export TestLoad
func TestLoad(cstr *C.char) **C.char {
    gostr := C.GoString(cstr)
    fmt.Println("In Go: ", gostr)
    goslice := []string{gostr, "i 0", "i 1", "i 2", "i 3"}
    cArray := C.malloc(C.size_t(len(goslice)) * C.size_t(unsafe.Sizeof(uintptr(0))))
    // defer C.free(unsafe.Pointer(cArray))
    temp := (*[1<<30 - 1]*C.char)(cArray)
    for k, v := range goslice {
        temp[k] = C.CString(v)
    }

    return (**C.char)(cArray)
}

func main() {
}

Python 端 -- 修改:POINTER(c_char_p * 5),然后调用 resp.contents 访问每个 python 字节。有关来源,请参阅 Example #17

from ctypes import *

mylib = cdll.LoadLibrary("./_mylib.so")
mylib.TestLoad.argtype = c_char_p
mylib.TestLoad.restype = POINTER(c_char_p*5)      

pystr = "Hello, world!"                             
b = pystr.encode("utf-8")                      
resp = mylib.TestLoad(b)  
        
'''**********************************'''
output = []
for seq in resp.contents:
    s = seq.decode("utf-8")
    output.append(s)
    print(s,type(s))
print(output)
'''**********************************'''

出现新问题:

在这个例子中,注释 // defer C.free(unsafe.Pointer(cArray)) 会导致 C 端内存泄漏吗?