トップページに戻る

pythonからC言語関数の呼び出し

 pythonからは、以下の手順でC言語で書かれたプログラムを呼び出すことができます。

  1. Cプログラム hogehoge.c を作成し、関数 double func(double a, int i, double b[]) を作る。
  2. hogehoge.c をコンパイルして dynamic link library (Windows, .dll) / shared library (Linux, .so) を作る
    この際、DLLから呼び出す関数は export する。
  3. pythonでは、ctypesモジュールをimportし、CDLL() あるいは WinDLL() 関数を使って DLL を読み込む
  4. pythonから呼び出す関数の引数、戻り値の定義 (プロトタイプの定義) を行う
    c_double (浮動小数点型), c_int (整数型), POINTER(c_double) (浮動小数点型のポインタ/配列変数のポインタ) を使って、変数型を指定する。
  5. C関数に渡す変数は、浮動小数点型、整数型は、型を合わせてそのまま渡せる。
    関数の呼び出し引数にポインタを渡して値を受け取るときは、byref(c_double) (浮動小数点型のポインタ) に変換する
    pythonのリスト型を渡すときは、例えば (c_double * ndata)(*data) に変換する
  6. C関数を呼び出す

1. Cプログラムの例

hogehoge.c:

#include <stddef.h>

double func(double a[], int size) {
  double sum = 0.0;
  int i;

  for (i = 0; i < size; i++) {
    sum += a[i];
  }

  return sum;
}

2. Cプログラムのコンパイル

Windowsの場合: exportする関数を hogehoge.def に定義する (Linuxでは不要)
           .defファイルを使わない場合、Cソースプログラムの関数定義に __declspec(dllexport) をつけるとexportされる

hogehoge.def:

LIBRARY "hogehoge"            # DLLの内部名。基本的にCプログラムファイル名、DLL名と同じ
EXPORTS    
  hogehoge                          # exportする関数

・ gcc を使う場合

> gcc.exe -shared -o hogehoge.dll hogehoge.c hogehoge.def

・ Intel oneAPIコンパイラを使う場合

> icl.exe hogehoge.c -link -dll -def:hoghoge.def -out:hogehoge.dll

# いずれのコンパイラでも、マクロを定義する場合は -D オプションを使える。 例: -DMAKE_DLL

 

Linuxの場合: 一般的に shared library の拡張子は .so

.defファイルは使えないので、exportする関数の宣言に __attribute__((visibility("default"))) をつけ、リンク時に -fPIC オプションを指定する。
また、math libraryをリンクするときは -lm を指定する。
以下の例では、Linux特有の設定を LINUX マクロを使っている場合。

> gcc -DMAKE_DLL -DLINUX -fPIC -shared -o $file.so $file.c -lm
> gcc -DMAKE_DLL -DLINUX -o $file $file.c -lm
 

3. pythonからの呼び出し

from ctypes import CDLL, c_double, c_int, POINTER        # ctypesモジュールから必要な関数・変数をimport

lib = CDLL('./hogehoge.dll')        # Windowsの場合。DLLを読み込む
lib = CDLL('./hogehoge.so')        # Linuxの場合。DLLを読み込む

lib.hogehoge.argtypes = (POINTER(c_double), c_int)        # 関数のプロトタイプを設定
lib.hogehoge.restype = c_double                                  # 戻り値の型を設定

data = [1.0, 2.0, 3.0, 4.0]
ndata = len(data)
c_array = (c_double * ndata)(*data)            # 浮動小数値元型の配列を渡す場合は、pythonのlistを変換する

result = lib.hogehoge(c_array, len(data))
print(result)

3'. より複雑な関数の呼び出し

C言語の関数定義: ポインタ引数に値を返す場合

int func(double x, double y, double *ret)
{
  *ret = x * y;
  return 1;
}

pythonからの呼び出し

from ctypes import CDLL, c_double, c_int, POINTER        # ctypesモジュールから必要な関数・変数をimport

lib = CDLL('./hogehoge.dll')        # DLLを読み込む

lib.hogehoge.argtypes = (POINTER(c_double), c_int)        # 関数のプロトタイプを設定
lib.hogehoge.restype = c_double                                  # 戻り値の型を設定

# 関数の引数と戻り値の型を設定
lib..func.argtypes = [c_double, c_double, POINTER(c_double)]
lib.func.restype = c_int

x = 2.0
y = 3.0
ret = c_double()
result = lib.func(x, y, byref(ret))
print("result=", result)
print("ret=", ret)