[英]Ctypes: Mapping a returned pointer to a structure
I have tried reading all the questions/answers on this topic but I could not get anything to work.我已尝试阅读有关此主题的所有问题/答案,但无法进行任何工作。 All I am trying to do is send a structure to a shared object, and then have it returned and be accessible.
我要做的就是将一个结构发送到一个共享的 object,然后让它返回并可以访问。
I have managed to create a structure OK, and I can pass it fine to the shared object.我已经成功地创建了一个结构,我可以将它很好地传递给共享的 object。 I know this as it works fine if returning a specific value from the structure.
我知道这一点,因为如果从结构中返回特定值,它工作正常。 The structure definition in Python can be seen below:
Python中的结构体定义如下:
class ROW(ctypes.Structure):
_fields_ = [("Address",ctypes.c_int16),
("FirstRegister",ctypes.c_int16),
("NumberOfRegisters",ctypes.c_int16),
("Sampling", ctypes.c_int16)]
class CONNECTOR(ctypes.Structure):
_fields_ = [("NumberOfRows", ctypes.c_int16),
("Rows", ROW * 200)]
# Initialise an array of connectors (CON1, CON2, CON11, CON12)
ConArray = CONNECTOR * 4
con = ConArray()
# Initialise an array of ROW struct
RowArray = ROW * 200
row = RowArray()
I then populate the structure with data from an SQLite database and can access the specific data using con[n].Rows[m].Address
etc.然后,我使用 SQLite 数据库中的数据填充结构,并可以使用
con[n].Rows[m].Address
等访问特定数据。
I am currently trying to just send one connector at a time, and return the exact same structure.我目前正在尝试一次只发送一个连接器,并返回完全相同的结构。
The relevant code can be seen below:相关代码如下:
testlib = ctypes.cdll.LoadLibrary('_example.so')
x = testlib.square_array
x.argtype = ctypes.POINTER(CONNECTOR)
x.restype = ctypes.POINTER(CONNECTOR)
y = x(ctypes.byref(con[0]))
I have tried many different methods of calling the function but this one seems to be the most promising.我尝试了许多不同的方法来调用 function 但这似乎是最有希望的。 The problem is when I try and then access specific values with
y.Rows[0].Address[0]
, an error occurs: AttributeError: 'LP_CONNECTOR' object has no attribute 'Rows'
.问题是当我尝试然后使用
y.Rows[0].Address[0]
访问特定值时,会发生错误: AttributeError: 'LP_CONNECTOR' object has no attribute 'Rows'
。
If instead, I just call the function directly:相反,我只是直接调用 function :
x = testlib.square_array(ctypes.byref(con[0]))
I receive an int
which I assume represents a memory address, eg: 35664848
.我收到一个
int
,我假设它代表一个 memory 地址,例如: 35664848
。
I have tried all sorts of options but I am quite unfamiliar with C (a colleague will be handling all the C side of code).我尝试了各种选择,但我对 C 非常不熟悉(一位同事将处理代码的所有 C 方面)。 Is there any proposed solutions?
有没有建议的解决方案? I feel like I am just missing one small thing, but it has took me many days just to reach this point.
我觉得我只是错过了一件小事,但我花了很多天才达到这一点。
Update: Added C code更新:添加了 C 代码
The C code can be seen below: C代码如下:
example.c:示例.c:
#include "example.h"
CONNECTOR* square_array(CONNECTOR* con)
{
printf("Value of Row 0 Address%i\n",con->Rows[0].Address);
return (con);
}
example.h:例子.h:
struct ROW;
struct CONNECTOR;
typedef struct {
short int Address;
short int FirstRegister;
short int NumberOfRegisters;
short int Sampling;
}ROW;
typedef struct {
short int NumberOfRows;
ROW Rows[200];
}CONNECTOR;
CONNECTOR Connectors[4];
I already created a small example of my own.我已经创建了一个自己的小例子。 After taking a closer look at the Python code, I could figure out the function header (and I also added some dummy body).
在仔细查看Python代码后,我可以找出 function header (我还添加了一些假体)。
The problem is simple, the function returns a CONNECTOR pointer, in order to access its members, you need to "dereference" it first, otherwise you'll get the AttributeError .问题很简单,function 返回一个CONNECTOR指针,为了访问它的成员,你需要先“取消引用”它,否则你会得到AttributeError 。 Here's your code (a little bit modified):
这是您的代码(稍作修改):
testlib = ctypes.cdll.LoadLibrary("_example.so")
testfunc = testlib.square_array
testfunc.argtypes = (ctypes.POINTER(CONNECTOR),)
testfunc.restype = ctypes.POINTER(CONNECTOR)
pconnector0 = testfunc(ctypes.byref(con[0]))
connector0 = pconnector0.contents
print(connector0.NumberOfRows)
print(connector0.Rows[0].Address)
The "secret" lies in pconnector0.contents which performs the "dereferencing". “秘密”在于执行“取消引用”的pconnector0.contents 。
As a side note the line of code y.Rows[0].Address[0] will trigger a TypeError because of the [0] at the end: Address is an int and can't be indexed (doesn't define __getitem__ ).作为旁注,代码行y.Rows[0].Address[0]将触发TypeError因为末尾的[0] : Address is an int and can't be indexed (doesn't define __getitem__ ) .
Regarding the second approach (calling the function directly), it's the same problem.关于第二种方法(直接调用function),也是同样的问题。 Here's some working code:
这是一些工作代码:
pconnector1 = testlib.square_array(ctypes.byref(con[0]))
connector1 = pconnector1.contents
print(type(connector1))
Notes :备注:
I used Python 2.7.10 on Win 10 pc064 , but nothing here should be Python version or platform specific我在Win 10 pc064上使用了 Python 2.7.10 ,但这里没有任何内容应该是Python版本或平台特定的
There's a typo with potential disastrous effects in your code.您的代码中有一个可能造成灾难性影响的错字。 Check [SO]: C function called from Python via ctypes returns incorrect value (@CristiFati's answer) for more details
检查[SO]:C function 通过 ctypes 从 Python 调用返回不正确的值(@CristiFati 的答案)以获取更多详细信息
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.