Ctypes를 이용한 Python과 C와의 연결


속도나 하드웨어 디바이스 드라이버 접근 등을 위해서 C와 연결해서 Python을 사용해야 할 일들은 생기기 마련이다.
두 언어를 이어 붙이기 위한 수단인 이종 언어간 인터페이스 (Foreign Function Interface, FFI)를 다룬다.

FFI를 지원하는 방법으로는 ctypes CFFI 방법이 있다.

  • ctypes방법은 파이썬 표준 라이브러리에 포함되어 있다.
    • C로 작성된 코드가 Shared object (*.so)형태로 컴파일 되어 있어야함.
    • 함수와 구초제 등을 ctypes에 맞는 방식으로 다시 정리해야된다.
    • OS에서 제공하는 symbol lookup 방식으로 찾을 수 있는 요소에 한해서만 접근이 가능함

C코드 스타일로 예제 작성

값을 카운트 하는 코드

int simple_function(void) {
    static int counter = 0;
    counter++;
    return counter;
}

문자열 하나 하나를 입력해서 string으로 변환함.

void add_one_to_string(char *input) {
    int ii = 0;
    for (; ii < strlen(input); ii++) {
        input[ii]++;
    }
}

두 개의 함수는 string을 C 컨텍스트 안에서 allocate 하고 free 하는 기능을 가진다.

char * alloc_C_string(void) {
    char* phrase = strdup("I was written in C");
    printf("C just allocated %p(%ld):  %s\n",
           phrase, (long int)phrase, phrase);
    return phrase;
}

void free_C_string(char* ptr) {
    printf("About to free %p(%ld):  %s\n",
           ptr, (long int)ptr, ptr);
    free(ptr);
}

Python에서 해당 ctypes 모듈을 loading하는 방법

기본적인 form은 아래와 같다.
그냥 같은 위치에 .so가 존재 한다면 아래와 같이 간단하게 읽어 올 수 있다.
다른 경로라면 다양한 방법으로 os package를 이용해서 path를 생성할 수 있다.

import ctypes

# Load the shared library into c types.
libc = ctypes.CDLL("./libclib1.so")

예를 들면 아래와 같이 처리 할 수 있다.

libname = os.path.abspath(
    os.path.join(os.path.dirname(__file__), "libclib1.so"))

libc = ctypes.CDLL(libname)

호출 방법 (기본)

파라메터 없이 호출하는건 간단하게 수행 된다.

import ctypes

# Load the shared library into c types.
libc = ctypes.CDLL("./libclib1.so")

# Call the C function from the library
counter = libc.simple_function()

여기서 int를 c에서 반환하고 이것은 ctypes에서 이러한 type부분을 python에 맞게 적절하게 변환해 준다.

Makefile 및 실행 결과

Makefile

all: test

clean:
  rm -f *.o *.so

clib1.so: clib1.o
  gcc -shared -o libclib1.so clib1.o

clib1.o: clib1.c
  gcc -c -Wall -Werror -fpic clib1.c

test clib1.so
  ./callclib1.py

실행 결과

./callclib1.py
Calling simple C counting function four times:
1
2
3
4

참고문헌


+ Recent posts