如何通过 C 在用户定义的结构中编写双数组并使用 CTYPE 传递给 Python

how to write double array in a user-defined structure by c and pass to python with ctype

本文关键字:数组 CTYPE Python 用户 何通过 定义 结构      更新时间:2023-10-16

我的目标是对结构成员进行C写入,并将结构指针传递回python。 该结构由 2 个相同大小的双精度数组(代表实部和 imag 部分数据,( # 数组中的行,# 的列。 由于它在 Python 中是行主,我可以按类型传递 2d 数组 指针(double(,并且给定 row&col,我可以访问正确的位置。(而不是指针(指针(c_double(((

在蟒蛇中

class tx_data(Structure):
_fields_=[("I", POINTER(c_double)), ("m", c_int), ("n", c_int), ("Q", POINTER(c_double))]
# argtypes& restype for preventing invalid data
writereturn = lib.WriteReturn
writei= lib.WriteI
writereturn.argtypes = [c_int,c_int]
writereturn.restype=POINTER(tx_data)
writei.argtypes = [c_int,c_int,POINTER(tx_data)]
writei.restype= None

函数 WriteI 传递具有零填充数据的结构实例,我希望数组由 C 填充数据。但是,数据没有改变。我不确定是否无法传递结构指针,并且结构还包含指向双精度的指针

def WriteI(Nrow, len):
txData_pointer = POINTER(tx_data)
rec_data = tx_data()
I = np.zeros((Nrow,len), dtype=np.double)
Q = np.zeros((Nrow,len), dtype=np.double)
rec_data.I = I.ctypes.data_as(POINTER(c_double))
rec_data.Q = Q.ctypes.data_as(POINTER(c_double))
rec_data.m = c_int(Nrow)
rec_data.n = c_int(len)
print(addressof(rec_data))
print(txData_pointer.from_address(addressof(rec_data)))
print("in PY--m:%d, n:%d"%(Nrow,len))
writei(Nrow, len, txData_pointer.from_address(addressof(rec_data)))
#rx(Nrow, len, byref(rec_data))
return rec_data

然后我看到了其他帖子,通过指针(结构(返回写入数据。我尝试如下,但弹出OSError:异常:访问违规写入0x0000000000000000

def WriteReturn(Nrow, len):
rec_data = tx_data.from_address(writereturn(Nrow, len))
xk = tx_data()
xk.I = cast(rec_data.contents.I, POINTER(c_double))
xk.Q = cast(rec_data.contents.Q, POINTER(c_double))
xk.m = c_int(Nrow)
xk.n = c_int(len)
return xk

在标题中

typedef struct{
double *I;
int m;
int n;
double *Q;
}tx_data;
extern "C" __declspec(dllexport) void WriteI(int Nrow, int len, tx_data &xk); 
extern "C" __declspec(dllexport) tx_data* WriteReturn(int Nrow, int len);

在C++

void WriteI(int Nrow, int len, tx_data &xk) {
size_t t;
for (int i = 0; i < Nrow; i++) {
for (int j = 0; j < len; j++) {
t = len * i + j;
xk.I[t] = 0.3+t;
xk.Q[t] = 0.7+t;
}
}
}
tx_data* WriteReturn(int Nrow, int len) {
tx_data* xk = new tx_data();
size_t t;
xk->m = Nrow;
xk->n = len;
for (int i = 0; i < Nrow; i++) {
for (int j = 0; j < len; j++) {
t = len * i + j;
xk->I[t] = 0.3 + t;
xk->Q[t] = 0.7 + t;
}
}
return xk;
}

谁能阐明如何解决它?

这里有很多问题。

首先,txData_pointer.from_address(addressof(rec_data))错了。这基本上是*(tx_data **)&rec_data的 C 等价物,这显然是错误的,因为rec_data不是指针。如果你想无缘无故地复杂,那就做tx_data.from_address(addressof(rec_data)),但如果你想简单,那就做byref(rec_data)

在那之后,tx_data.from_address(writereturn(Nrow, len))错了。这里没有必要涉及from_address;只需保存writereturn的结果即可。

接下来,void WriteI(int Nrow, int len, tx_data &xk)错了。不能在声明extern "C"的函数签名中使用&。使用*而不是&,并将WriteI更改为使用xk->而不是xk.

最后,在WriteReturn中,您正在创建一个新的tx_data,但不会为其分配IQ,尽管尝试写入它们。你需要做xk->I = new double[Nrow * len];Q也是如此。

修复所有这些后,您的代码就可以工作了。这是修复程序(您在 Python 中的class按原样很好,所以我没有重新发布它(:

def WriteI(Nrow, len):
rec_data = tx_data()
I = np.zeros((Nrow,len), dtype=np.double)
Q = np.zeros((Nrow,len), dtype=np.double)
rec_data.I = I.ctypes.data_as(POINTER(c_double))
rec_data.Q = Q.ctypes.data_as(POINTER(c_double))
rec_data.m = c_int(Nrow)
rec_data.n = c_int(len)
print(addressof(rec_data))
print("in PY--m:%d, n:%d"%(Nrow,len))
writei(Nrow, len, byref(rec_data))
#rx(Nrow, len, byref(rec_data))
return rec_data
def WriteReturn(Nrow, len):
rec_data = writereturn(Nrow, len)
xk = tx_data()
xk.I = cast(rec_data.contents.I, POINTER(c_double))
xk.Q = cast(rec_data.contents.Q, POINTER(c_double))
xk.m = c_int(Nrow)
xk.n = c_int(len)
return xk
typedef struct{
double *I;
int m;
int n;
double *Q;
}tx_data;
extern "C" __declspec(dllexport) void WriteI(int Nrow, int len, tx_data *xk);
extern "C" __declspec(dllexport) tx_data* WriteReturn(int Nrow, int len);
void WriteI(int Nrow, int len, tx_data *xk) {
size_t t;
for (int i = 0; i < Nrow; i++) {
for (int j = 0; j < len; j++) {
t = len * i + j;
xk->I[t] = 0.3+t;
xk->Q[t] = 0.7+t;
}
}
}
tx_data* WriteReturn(int Nrow, int len) {
tx_data* xk = new tx_data();
size_t t;
xk->I = new double[Nrow * len];
xk->m = Nrow;
xk->n = len;
xk->Q = new double[Nrow * len];
for (int i = 0; i < Nrow; i++) {
for (int j = 0; j < len; j++) {
t = len * i + j;
xk->I[t] = 0.3 + t;
xk->Q[t] = 0.7 + t;
}
}
return xk;
}

顺便说一下,你可以做很多事情来改进这段代码,我没有介绍。这只是使其工作所需的最低限度的更改。