4

Pythonを使用してアクセスしたい自作のCライブラリがあります。問題は、コードが基本的に 2 つの部分で構成されていることです。多数のファイルからデータを読み込むための初期化と、一度だけ実行する必要があるいくつかの計算です。他の部分はループで呼び出され、以前に生成されたデータを繰り返し使用します。この関数に、Python からパラメーターを渡したいと思います。

私のアイデアは、「init」と「loop」という 2 つの C ラッパー関数を作成することでした。「init」はデータを読み取り、構造体への void ポインターを返します。これは、「loop」が Python から渡すことができる追加のパラメーターと一緒に使用できます。何かのようなもの

void *init() {
  struct *mystruct ret = (mystruct *)malloc(sizeof(mystruct));
  /* Fill ret with data */
  return ret;
}

float loop(void *data, float par1, float par2) {
  /* do stuff with data, par1, par2, return result */
}

c_void_p として python から「init」を呼び出してみましたが、「ループ」は「データ」の内容の一部を変更し、ctypes の void ポインターは不変であるため、これは機能しませんでした。

私が見た同様の問題に対する他の解決策は、「init」がどれだけのメモリを使用するかを知る必要があるようですが、私はそれを知りません。

あるC関数から別のC関数にPythonを介してデータを渡す方法はありますか? または、私の問題を解決する別の方法はありますか?


私は最小限のクラッシュの例を書こうとしました (そして失敗しました) が、いくつかのデバッグの後、私の C コードにバグがあることが判明しました。答えてくれたみんなありがとう!これが他の人に役立つことを願って、これは一種の最小限の作業バージョンです(まだ個別の「無料」はありません-申し訳ありません):

pybug.c:

#include <stdio.h>
#include <stdlib.h>

typedef struct inner_struct_s {
  int length;
  float *array;
} inner_struct_t;

typedef struct mystruct_S {
  int id;
  float start;
  float end;
  inner_struct_t *inner;
} mystruct_t;

void init(void **data) {
  int i;
  mystruct_t *mystruct = (mystruct_t *)malloc(sizeof(mystruct_t));
  inner_struct_t *inner = (inner_struct_t *)malloc(sizeof(inner_struct_t));
  inner->length = 10;
  inner->array = calloc(inner->length, sizeof(float));
  for (i=0; i<inner->length; i++)
    inner->array[i] = 2*i;
  mystruct->id = 0;
  mystruct->start = 0;
  mystruct->end = inner->length;
  mystruct->inner = inner;
  *data = mystruct;
}

float loop(void *data, float par1, float par2, int newsize) {
  mystruct_t *str = data;
  inner_struct_t *inner = str->inner;
  int i;
  inner->length = newsize;
  inner->array  = realloc(inner->array, newsize * sizeof(float));
  for (i=0; i<inner->length; i++)
    inner->array[i] = par1 + i * par2;
  return inner->array[inner->length-1];
}

としてコンパイル

cc -c -fPIC pybug.c
cc -shared -o libbug.so pybug.o

Python で実行します。

from ctypes import *
sl = CDLL('libbug.so')
# What arguments do functions take / return?
sl.init.argtype = c_void_p
sl.loop.restype = c_float
sl.loop.argtypes = [c_void_p, c_float, c_float, c_int]

# Init takes a pointer to a pointer
px = c_void_p()
sl.init(byref(px))

# Call the loop a couple of times
for i in range(10):
    print sl.loop(px, i, 5, 10*i+5)
4

2 に答える 2