2012-04-26 2 views
1

struct a { }이 정의되어 있습니다. 내 C 함수는 struct a 배열을 참조로 가져온 다음 데이터를 채 웁니다. 따라서 인수는 struct a **입니다. 필자는 SWIG 인터페이스를 사용하여이 함수를 파이썬에서 호출하려고합니다. 그렇게 할 수있는 방법이 있습니까?포인터 배열을 사용하는 함수 줄 바꾸기

답변

4

SWIG 및 Python으로이 작업을 수행 할 수 있습니다. 나는 deomstrate 다음 test.h 파일을 설정 한 :

struct a { 
    int val; 
}; 

static void populate(struct a **list) { 
    int count = 0; 
    // Terminate when NULL entry found 
    while (*list) { 
    (*list)->val = count++; 
    ++list; 
    } 
} 

채우기 기능 목록이 NULL 종료된다고 가정하면, 당신이 설명으로 struct a**를 받아리스트의 각 요소에 뭔가를한다.

내가 이것을 파이썬에 드러내는 방법은 정수를 취하는 함수, 즉리스트의 크기를 가지고 함수 목록의 결과를 반환하는 함수였다. 내 견해에서 설정 한 "논쟁을 통해 반환".

%typemap(in,numinputs=1) struct a ** (int len=0) { 
    len = (int)PyInt_AsLong($input); 
    $1 = malloc(sizeof(struct a*)*(len+1)); 
    $1[len] = NULL; 
    for (int i = 0; i < len; ++i) { 
    $1[i] = malloc(sizeof(struct a)); 
    } 
} 

은 기본적으로는 인수를 취급 :

%module test 

%{ 
#include "test.h" 
%} 

다음 파이썬 함수에 지정된 크기에 따라 입력 목록을 준비하는 타입 맵을 추가 :

나는 기본 모듈 파일을 설정 정수로 포인터 배열에 메모리를 할당 한 다음 요소 자체가 가리키는 개체에 대해 메모리를 할당합니다. (나는 SWIG/Python이 개별적으로 각각의 항목에 대한 참조 계산을 처리 할 수 ​​있도록 개별적으로 할당했다. 모든 요소에 대해 하나의 블록을 할당하는 것보다 간단하다)

작성된 typemap을 사용하여 나는 또 다른 typemap을 추가했다. 함수를 호출의 결과를 측정하고 PyList로 다시 변환 :

%typemap(argout) struct a ** { 
    // Push into PyList for return 
    $result = PyList_New(len$argnum); 
    for (int i = 0; i < len$argnum; ++i) { 
    PyObject *element = SWIG_NewPointerObj(SWIG_as_voidptr($1[i]), SWIGTYPE_p_a, SWIG_POINTER_OWN); 
    PyList_SET_ITEM($result, i, element); 
    } 
} 

그것의 NULL 종료 이후 우리가 다시 길이를 계산 만있을 수 있지만 그것은, 우리는 타입 맵에서에서 만든 len 변수의 활용 . 그런 다음 populate 함수에 전달한 struct a 각각에 대해 파이썬 목록의 각 항목에 래핑 된 객체 (SWIG/Python 소유)를 채 웁니다. 유형 이름이 다른 경우 SWIGTYPE_p_a을 적절하게 SWIGTYPE으로 변경해야합니다. (이들은 생성 된 래퍼 소스에서 찾을 수 있습니다).

이러한적인 typemap를 사용하여 헤더 파일 자체를 포장 꿀꺽 꿀꺽에게 다음

%typemap(freearg) struct a ** { 
    free($1); 
} 

과 :

마지막으로 우리는, 우리는 C 측의 목록을 가지고 있던 메모리를 해제 할당해야

%include "test.h" 

나는 이것을 컴파일 : 다음

 
swig -python -Wall test.i 
gcc -Wall -Wextra test_wrap.c -I/usr/include/python2.6 -o _test.so -std=c99 -shared 

및 확인하려면 다음 파이썬을 실행 :

import test 

r=test.populate(100) 
print r[0].val 

여러 지점이 예에서 참고 : 오류 검사가 없습니다

  • 가, 나쁜 일을 할 것입니다 예를 test.populate("Hello world")를 들어, PyList_New이 실패 할 수 있습니다 우리가 개별 요소를 해제 할 필요가 실패하는 경우,
  • 메모리 소유권 의미가 다르면 SWIG_POINTER_OWN을 적절하게 변경해야합니다.
  • 파이썬 interfa에서 목록의 크기를 지정하지 않으려면 ce (예 : 그것은 다른 것으로 알려져 있거나 고정되어 있습니다) numinputs=1을 0으로 변경하고 in typmap에 따라 len을 설정할 수 있습니다.
  • 함수가 NULL 종료 목록을 사용하는 대신 길이와 길이를 지정하는 목록을 사용하는 경우이를 multi-argument typemap으로 확장 할 수 있습니다.

/컴파일이 예제를 실행하는 데 필요한 모든 코드이 대답에 포함되어 있지만 하나 개의 편리한 타르 그것을 원한다면 또한 on my site을 넣었습니다. 비록 그 링크가 깨져 야하더라도 대답은 여전히 ​​작동합니다.

+0

답해 주셔서 감사합니다. 며칠 전이 질문/답변을 찾았 으면 좋겠습니다. 나는 비슷한 것을 개발해야만했고 당신과 거의 같은 해결책을 찾았습니다. 대부분의 기술 문제가 이미 해결 된 또 다른 교훈은 ... –