在 C 程序中使用 cython 和 ctypes 接口调用 python 函数获取 'c' 类似结构
Calling python function fetching 'c' like struct using cython and ctypes interface in c program
我是 cython/ctypes 的新手,我正在尝试使用 cython 接口从 c 程序调用 python 函数,但数据为空或不正确。这是示例程序
python函数
$ cat c_struct.py
#!/usr/bin/env python2.7
from ctypes import *
class Request(Structure):
_pack_ = 1
_fields_ = [
('type', c_ubyte),
('subtype', c_ubyte),
('action', c_ubyte),
('checksum', c_ushort)
]
def __repr__(self):
return "'type': {}, 'subtype': {}, 'action': {}, 'checksum': {}".format(self.type,
self.subtype, self.action, self.checksum)
req_msg = Request()
def get_message(typ):
if typ == 1:
req_msg.type = 12
req_msg.subtype = 2
req_msg.action = 3
req_msg.checksum = 0x1234
return req_msg
else:
return "String object From Python"
cython 包装器
$ cat caller.pyx
import sys
sys.path.insert(0, '')
from c_struct import get_message
cdef public const void* get_data_frm_python(int typ):
data = get_message(typ)
print "Printing in Cython -",data
return <const void*>data
最后是我的 'C' 来电者
cat main.c
#include <Python.h>
#include "caller.h"
#include <stdio.h>
typedef struct {
uint8_t type;
uint8_t subtype;
uint8_t action;
uint16_t checksum;
} __attribute__ ((packed)) request_t;
int
main()
{
PyImport_AppendInittab("caller", initcaller);
Py_Initialize();
PyImport_ImportModule("caller");
const char* str = get_data_frm_python(2);
printf("Printing in C - %s\n", str);
const request_t* reqP = (request_t*)get_data_frm_python(1);
printf("Printing in C - %u, %u, %u, %u\n", reqP->type, reqP->subtype, reqP->action, reqP->checksum);
return 0;
}
和一个简单的 makefile 来构建它
$ cat Makefile
target = main
cy_interface = caller
CY := cython
PYTHONINC := $(shell python-config --includes)
CFLAGS := -Wall $(PYTHONINC) -fPIC -O0 -ggdb3
LDFLAGS := $(shell python-config --ldflags)
CC=gcc
all: $(target)
%.c: %.pyx
$(CY) $+
%.o: %.c
$(CC) -fPIC $(CFLAGS) -c $+
$(target): $(cy_interface).o $(target).o
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
最后输出:(
$ ./main
Printing in Cython - String object From Python
Printing in C -
Printing in Cython - 'type': 12, 'subtype': 2, 'action': 3, 'checksum': 4660
Printing in C - 1, 0, 0, 0
有人可以帮助我了解我做错了什么吗?
注意:- 如果我将 void* 更改为 char* 至少可以正确获取字符串数据,但 struct
会出现段错误
$ cat caller.pyx
import sys
sys.path.insert(0, '')
from c_struct import get_message
cdef public const void* get_data_frm_python(int typ):
data = get_message(typ)
print "Printing in Cython -",data
return <const char*>data
$ ./main
Printing in Cython - String object From Python
Printing in C - String object From Python
Printing in Cython - 'type': 12, 'subtype': 2, 'action': 3, 'checksum': 4660
TypeError: expected string or Unicode object, Request found
Exception TypeError: 'expected string or Unicode object, Request found' in 'caller.get_data_frm_python' ignored
Segmentation fault
<const void*>data
data
是一个 Python 对象(PyObject*
)。此行将 PyObject*
转换为 void。将 PyObject*
解释为字符串或 request*
.
绝对是不合理的
<const char*>data
这会得到一个指向 Python 字符串(您的结构不是)的第一个元素的指针。该指针仅在 data
仍然存在时有效。不幸的是,数据是一个函数局部变量,因此几乎可以立即释放。很难说清楚这里到底发生了什么,但这绝对是错误的。
我真的不明白你想在这里实现什么,所以我很难就如何做得更好提出建议。也许放弃 ctypes 并将 Cython 与 C 联合一起使用?
不管怎样,这对我有用,不是完美的,而是一些东西。
$ cat caller.pyx
import sys
sys.path.insert(0, '')
from libc.stdint cimport uintptr_t
from c_struct import get_message
cdef public const void* get_data_frm_python(int typ):
data = get_message(typ)
if isinstance(data, str):
return <const char*>(data)
cdef uintptr_t ptr = <uintptr_t>(get_message(typ))
return <const void*>(ptr)
def get_message(typ):
if typ == 1:
req_msg.type = 12
req_msg.subtype = 2
req_msg.action = 3
req_msg.checksum = 0x1234
return addressof(req_msg)
else:
return "String object From Python"
$ ./main
Printing in C - String object From Python
Printing in C - 12, 2, 3, 4660
我是 cython/ctypes 的新手,我正在尝试使用 cython 接口从 c 程序调用 python 函数,但数据为空或不正确。这是示例程序
python函数
$ cat c_struct.py
#!/usr/bin/env python2.7
from ctypes import *
class Request(Structure):
_pack_ = 1
_fields_ = [
('type', c_ubyte),
('subtype', c_ubyte),
('action', c_ubyte),
('checksum', c_ushort)
]
def __repr__(self):
return "'type': {}, 'subtype': {}, 'action': {}, 'checksum': {}".format(self.type,
self.subtype, self.action, self.checksum)
req_msg = Request()
def get_message(typ):
if typ == 1:
req_msg.type = 12
req_msg.subtype = 2
req_msg.action = 3
req_msg.checksum = 0x1234
return req_msg
else:
return "String object From Python"
cython 包装器
$ cat caller.pyx
import sys
sys.path.insert(0, '')
from c_struct import get_message
cdef public const void* get_data_frm_python(int typ):
data = get_message(typ)
print "Printing in Cython -",data
return <const void*>data
最后是我的 'C' 来电者
cat main.c
#include <Python.h>
#include "caller.h"
#include <stdio.h>
typedef struct {
uint8_t type;
uint8_t subtype;
uint8_t action;
uint16_t checksum;
} __attribute__ ((packed)) request_t;
int
main()
{
PyImport_AppendInittab("caller", initcaller);
Py_Initialize();
PyImport_ImportModule("caller");
const char* str = get_data_frm_python(2);
printf("Printing in C - %s\n", str);
const request_t* reqP = (request_t*)get_data_frm_python(1);
printf("Printing in C - %u, %u, %u, %u\n", reqP->type, reqP->subtype, reqP->action, reqP->checksum);
return 0;
}
和一个简单的 makefile 来构建它
$ cat Makefile
target = main
cy_interface = caller
CY := cython
PYTHONINC := $(shell python-config --includes)
CFLAGS := -Wall $(PYTHONINC) -fPIC -O0 -ggdb3
LDFLAGS := $(shell python-config --ldflags)
CC=gcc
all: $(target)
%.c: %.pyx
$(CY) $+
%.o: %.c
$(CC) -fPIC $(CFLAGS) -c $+
$(target): $(cy_interface).o $(target).o
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
最后输出:(
$ ./main
Printing in Cython - String object From Python
Printing in C -
Printing in Cython - 'type': 12, 'subtype': 2, 'action': 3, 'checksum': 4660
Printing in C - 1, 0, 0, 0
有人可以帮助我了解我做错了什么吗?
注意:- 如果我将 void* 更改为 char* 至少可以正确获取字符串数据,但 struct
会出现段错误$ cat caller.pyx
import sys
sys.path.insert(0, '')
from c_struct import get_message
cdef public const void* get_data_frm_python(int typ):
data = get_message(typ)
print "Printing in Cython -",data
return <const char*>data
$ ./main
Printing in Cython - String object From Python
Printing in C - String object From Python
Printing in Cython - 'type': 12, 'subtype': 2, 'action': 3, 'checksum': 4660
TypeError: expected string or Unicode object, Request found
Exception TypeError: 'expected string or Unicode object, Request found' in 'caller.get_data_frm_python' ignored
Segmentation fault
<const void*>data
data
是一个 Python 对象(PyObject*
)。此行将 PyObject*
转换为 void。将 PyObject*
解释为字符串或 request*
.
<const char*>data
这会得到一个指向 Python 字符串(您的结构不是)的第一个元素的指针。该指针仅在 data
仍然存在时有效。不幸的是,数据是一个函数局部变量,因此几乎可以立即释放。很难说清楚这里到底发生了什么,但这绝对是错误的。
我真的不明白你想在这里实现什么,所以我很难就如何做得更好提出建议。也许放弃 ctypes 并将 Cython 与 C 联合一起使用?
不管怎样,这对我有用,不是完美的,而是一些东西。
$ cat caller.pyx
import sys
sys.path.insert(0, '')
from libc.stdint cimport uintptr_t
from c_struct import get_message
cdef public const void* get_data_frm_python(int typ):
data = get_message(typ)
if isinstance(data, str):
return <const char*>(data)
cdef uintptr_t ptr = <uintptr_t>(get_message(typ))
return <const void*>(ptr)
def get_message(typ):
if typ == 1:
req_msg.type = 12
req_msg.subtype = 2
req_msg.action = 3
req_msg.checksum = 0x1234
return addressof(req_msg)
else:
return "String object From Python"
$ ./main
Printing in C - String object From Python
Printing in C - 12, 2, 3, 4660