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.
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:
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() {
}
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.
defer C.free...
locates should be commentedpackage 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() {
}
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)
'''**********************************'''
Would commenting // defer C.free(unsafe.Pointer(cArray))
cause memory leaking on the C-Side in this example case?