如何使用c在用户定义的结构中写入双精度数组并使用ctype传递给python

问题描述 投票:0回答:1

我的目标是C编写结构成员,然后将结构指针传递回python。该结构包含2个相同大小的双精度数组(分别代表实零件和imag零件数据),数组中的行数,列数。由于它在Python中是行主要的,因此我可以通过POINTER(double)类型传递2d数组,并且在给定row&col的情况下,我可以访问正确的位置。 (而不是POINTER(POINTER(c_double)))

在Python中

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填充数据。但是,数据没有改变。我不确定是否无法传递结构的指针,并且该结构也包含指向double的指针

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

然后,我看到了另一篇文章,通过POINTER(structure)返回了写入数据。我尝试如下操作,但弹出OSError:exception:Access Conflict Writing 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

在Header.h中

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;
}

有人可以阐明一些解决方法吗?

python c++ struct ctypes
1个回答
0
投票

这里有很多问题。

首先,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;
}

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

© www.soinside.com 2019 - 2024. All rights reserved.