ユーニックス総合研究所

  • home
  • archives
  • python-my-puts

PythonからC言語(my.puts)を呼び出して実行する

  • 作成日: 2021-07-26
  • 更新日: 2023-12-24
  • カテゴリ: Python

PythonからC言語(my.puts)を呼び出して実行する

PythonはC言語で書かれたモジュールを呼び出すことが出来ます。
この記事ではその方法を解説します。

簡単に言うと、まずC言語でモジュールを書きます。
このモジュールはPythoの規約に沿った書き方をする必要があります。
それからそのモジュールをgccなどのコンパイラでコンパイルして共有ライブラリにします。

コンパイルした共有ライブラリをPythonインタプリタからインポートして、定義したモジュールのメソッドを呼び出します。
これが一連の流れです。

C言語でモジュールを書く

C言語でモジュールを書くわけですが、今回は「my」モジュールと言うモジュールを作ります。
そして「puts」という関数をmyモジュールの中に定義します。

コードにすると↓のようになります。

/**  
 * my モジュール  
 *   
 * インポートすると puts 関数を使える  
 *   
 * コンパイル例:  
 *  gcc -I /usr/include/python3.5m -fPIC -Wall -shared -o my.so my.c  
 */  

// コンパイラのフラグ -I に Python.h のあるディレクトリを指定する必要がある  
#include <Python.h>   

/**  
 * my モジュールのメソッド  
 * 引数の文字列を標準出力に出力してその長さを返す  
 */  
PyObject* my_puts(PyObject* self, PyObject* args)  
{  
    const char* name;  

    // args をパースして name に値を保存する  
    // "s" は文字列を表す  
    // args を "s" でパースしろという命令  
    if (!PyArg_ParseTuple(args, "s", &name))  
        return NULL;  

    long len = strlen(name);  // 文字列の長さを取得  
    int result = puts(name);  // name を stdout に出力  
    if (result == EOF) {  // 結果が失敗だったら  
        len = result; // len に EOF(-1) を入れる  
    }  

    // 文字列の長さを返す  
    // PyLong_FromLong は整数オブジェクトを生成する  
    return PyLong_FromLong(len);  
}  

// モジュール内のメソッドを定義する  
// puts がメソッド名で my_puts がメソッドの本体  
// METH_VARARGS は引数の定義  
// 一番最後にメソッドの説明  
static PyMethodDef my_methods[] = {  
    {"puts", my_puts, METH_VARARGS, "Print argument string to stdout"},  
    {NULL},  // 番兵  
};  

// モジュールのドキュメント  
#define my_doc \  
    "My module is my module.\n"  

// モジュールの定義  
static struct PyModuleDef module =  
{  
    PyModuleDef_HEAD_INIT,  
    "my",  // モジュール名。インポートするときに使用される名前  
    my_doc,  // モジュールのドキュメント  
    -1,  // モジュールのインタプリタのステートのサイズ  
    my_methods  // モジュール  
};  

// モジュールの初期化  
// PyInit_(モジュール名)になる  
// 今回は my モジュールを作るので PyInit_my になる  
PyMODINIT_FUNC PyInit_my(void)  
{  
    return PyModule_Create(&module);  
}  

モジュールをコンパイルする

先ほどのモジュール(my.c)をコンパイルするには↓のようにします。

$ gcc -I /usr/include/python3.5m -fPIC -Wall -shared -o my.so my.c  

↑のように-sharedフラグを付けて共有ライブラリ(my.so)としてコンパイルします。
-Iフラグのパスは環境によって変わります。
筆者の環境では/usr/include/python3.5mディレクトリ以下にPython.hがあったので、ここを指定しています。

モジュールをインポートする

Pythonインタプリタを起動してモジュールをインポートし、puts()関数を実行します。

$ ls  
my.c my.so  

$ python  
import my  

result = my.puts("Hi")  
# Hi  

print(result)  
# 2  

以上のようにC言語で書かれたモジュールをPythonから呼び出すことが出来ました。

おわりに

Pythonではこのように簡単にC言語と連携を取ることが出来ます。
速度の必要な処理を書きたい場合はC言語を使えばいいわけですね。

🦝 < 便利だな~

🐭 < Python様様