英文:
from **char to python list
问题
我已经解决了这个问题,请查看我在问题下面的回答。
但是我最终发现将Go函数嵌入到Python中非常愚蠢。这种嵌入失败的主要原因是Go函数很难知道何时回收内存资源,从而导致内存泄漏。
目前,我认为将它们结合在一起的最佳方法可能是通过消息通信,比如使用sockets。
如果我的想法有误,请告诉我任何正确的信息。
原始问题:
在C端,一个函数返回一个字符串数组(例如["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) # ***是否可能有两个或更多的返回类型?***
pystr = "hello" # python str
b = pystr.encode("utf-8") # 将str转换为bytes
resp = mylib.TestLoad(b) # 调用CGo函数,并获得类型为POINTER(c_char_p)的resp
list_len = 5 # 假设列表的长度是已知的
'''
TODO
'''
顺便问一下,一个C或CGO函数是否可能有两个或更多的返回值?我尝试过但无法编译通过。
谢谢帮助。
英文:
I've solved the problem, please see my answer below the question.
But I finally found it very stupid to embed GO functions into Python. This kind of embedding fails mainly because Go function can hardly know when to recycling memory resources, and thus results in memory leaking.
At present, I realize that the best way to combine them together might be message communicating, like socks.
Please tell me anything correct if my thought is wrong.
Original Question:
At C side, a function returns an array of strings (say ["i 0","i 1","i 2","i 3"]), type is **char
.
At Python side, that **char
output is read into a variable (say cArray
), with the type POINTER(c_char_p)
My question: How to create a python list from cArray
? that is obtaining pylist == ["i 0","i 1","i 2","i 3"]
I also wonder if there is a value taking operation in python, like * operation in C.
Following is the code example:
C side (actually 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 side
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
'''
BTW, is it possible to have two or more returns for a single C or CGO function? I tried but failed to complile.
Thanks for help.
答案1
得分: 0
解决方案:
C端(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-bytes。参见 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端内存泄漏吗?
英文:
Solution:
C side (GO) -- the line where defer C.free...
locates should be commented
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 side -- revised: POINTER(c_char_p * 5), then call resp.contents to access each python-bytes. See Example #17 for the source.
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)
'''**********************************'''
A new question arises:
Would commenting // defer C.free(unsafe.Pointer(cArray))
cause memory leaking on the C-Side in this example case?
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论