簡體   English   中英

使用Python ctypes運行C dll函數時遇到問題(數組輸出大小未知)

[英]Trouble using Python ctypes to run C dll function (array output with unknown size)

我正在嘗試使用 Python ctypes 執行 C 函數,但我做錯了。

C 函數最初是使用 MATLAB 編碼器從 MATLAB 轉換為 C 代碼的。 該函數給出一個未定義長度的數組作為輸出,該數組取決於輸入。

這是MATLAB代碼:

function a = array_output(n)
%$codegen

if n > 2*pi
    a = 1:n;
else
    a = [1,2,3];
end

end

這是獲得的C代碼:

void array_output(double n, emxArray_real_T *a)
{
  int i;
  int loop_ub;
  if (n > 6.2831853071795862) {
    i = a->size[0] * a->size[1];
    a->size[0] = 1;
    loop_ub = (int)floor(n - 1.0);
    a->size[1] = loop_ub + 1;
    emxEnsureCapacity_real_T(a, i);
    for (i = 0; i <= loop_ub; i++) {
      a->data[i] = (double)i + 1.0;
    }
  } else {
    i = a->size[0] * a->size[1];
    a->size[0] = 1;
    a->size[1] = 3;
    emxEnsureCapacity_real_T(a, i);
    a->data[0] = 1.0;
    a->data[1] = 2.0;
    a->data[2] = 3.0;
  }
}

struct emxArray_real_T
{
  double *data;
  int *size;
  int allocatedSize;
  int numDimensions;
  boolean_T canFreeData;
};

請在我的問題末尾找到他們提供的示例實現。

我正在嘗試使用以下代碼使用 Python 的 ctype 執行它:

dll = ctypes.cdll.LoadLibrary(dll_path)


class DataStruct(ctypes.Structure):
    _fields_ = [
        ('data', ctypes.POINTER(ctypes.c_double)),
        ('size', ctypes.POINTER(ctypes.c_int)),
        ('allocatedSize', ctypes.c_int),
        ('numDimensions', ctypes.c_int),
        ('canFreeData', ctypes.c_bool)
    ]


array = ctypes.POINTER(ctypes.c_double)()
size = numpy.array([0, 0]).ctypes.data_as(ctypes.POINTER(ctypes.c_int))
allocatedSize = 0
numDimensions = 2
canFreeData = True

data_struct = DataStruct(array, size, allocatedSize, numDimensions, canFreeData)

dll.array_output.argtypes = [ctypes.c_double, DataStruct]
dll.array_output.restype = None

dll.array_output(50, data_struct)

輸出data_struct包含正確的大小字段( data_struct.size[1]是 50),但是當我嘗試訪問data_struct.data[0] ,出現以下錯誤:

ValueError: NULL pointer access

誰能幫助我理解我在這里做錯了什么?

——

示例實現(代碼片段):

void main(){
    // pseudo-code here
    emxArray_real_T *a;
    emxInitArray_real_T(&a, 2);
    
    /* Initialize function 'array_output' input arguments. */
    /* Call the entry-point 'array_output'. */
    array_output(5.0, a);
}

void emxInitArray_real_T(emxArray_real_T **pEmxArray, int numDimensions)
{
  emxInit_real_T(pEmxArray, numDimensions);
}

void emxInit_real_T(emxArray_real_T **pEmxArray, int numDimensions)
{
  emxArray_real_T *emxArray;
  int i;
  *pEmxArray = (emxArray_real_T *)malloc(sizeof(emxArray_real_T));
  emxArray = *pEmxArray;
  emxArray->data = (double *)NULL;
  emxArray->numDimensions = numDimensions;
  emxArray->size = (int *)malloc(sizeof(int) * numDimensions);
  emxArray->allocatedSize = 0;
  emxArray->canFreeData = true;
  for (i = 0; i < numDimensions; i++) {
    emxArray->size[i] = 0;
  }
}


void emxEnsureCapacity_real_T(emxArray_real_T *emxArray, int oldNumel)
{
  int newNumel;
  int i;
  void *newData;
  if (oldNumel < 0) {
    oldNumel = 0;
  }

  newNumel = 1;
  for (i = 0; i < emxArray->numDimensions; i++) {
    newNumel *= emxArray->size[i];
  }

  if (newNumel > emxArray->allocatedSize) {
    i = emxArray->allocatedSize;
    if (i < 16) {
      i = 16;
    }

    while (i < newNumel) {
      if (i > 1073741823) {
        i = MAX_int32_T;
      } else {
        i *= 2;
      }
    }

    newData = calloc((unsigned int)i, sizeof(double));
    if (emxArray->data != NULL) {
      memcpy(newData, emxArray->data, sizeof(double) * oldNumel);
      if (emxArray->canFreeData) {
        free(emxArray->data);
      }
    }

    emxArray->data = (double *)newData;
    emxArray->allocatedSize = i;
    emxArray->canFreeData = true;
  }
}

array_output的第二個參數是emxArray_real_T * ,但您試圖按值傳遞結構,就好像它只是一個emxArray_real_T 要解決此問題, dll.array_output.argtypes = [ctypes.c_double, DataStruct]更改為dll.array_output.argtypes = [ctypes.c_double, ctypes.POINTER(DataStruct)]並將dll.array_output(50, data_struct)更改為dll.array_output(50, ctypes.byref(data_struct))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM