greenteaの日記: python ctypes使ってみた。
Pythonには、Cのライブラリを読み込んで使える「ctypes」とかいう便利なライブラリがあるらしい。
WindowsでもLinuxでも使えるみたい。
http://starship.python.net/crew/theller/ctypes/
http://ymasuda.jp/python/ctypes/ctypes_jp.html
アホなので、チュートリアルとリファレンス読んでもイマイチ理解できなかった。
なので、いろいろと使ってみた。
>>> from ctypes import * # これがなくちゃ始まらない。
とりあえず、libcを読み込む。
>>> libc = cdll.LoadLibrary("libc.so.6")
>>> libc
例のアレ。
>>> libc.printf("hello, world\n")
hello, world
13
こんな風に、
LoadLibrary(Library path)
でライブラリが読み込まれた(っていうのかな?)CDLL型オブジェクトが返ってくる。で、
cdll_obj.function_name(args...)
とすると、cdll_objectに読み込まれたライブラリが持つ関数を呼び出し。
int型を作ってみる
>>> ci = c_int(100)
>>> ci
c_long(100)
うちではc_int型とc_long型は同じらしい。
>>> ci = ci+ci
Traceback (most recent call last):
File "", line 1, in
TypeError: unsupported operand type(s) for +: 'c_long' and 'c_long'
c_int同士の足し算(試してないが、恐らく他の演算も)はできない。
>>> ci+1
Traceback (most recent call last):
File "", line 1, in
TypeError: unsupported operand type(s) for +: 'c_long' and 'int'
c_intと数字の足し算(試してないが、恐らく他の演算も)もできない。
>>> ci.value
100
c_int_obj.value
で元の中身がみれる。
ということは、
>>> ci = c_int(ci.value + 10)
>>> ci
c_long(110)
で足し算ができる。
ところで、
>>> libc.printf("%d, %d\n", 10, c_int(10))
10, 10
7
c_int使わなくてもできるやん。
c_intじゃないと無理なことを考えてみた。
→c_intじゃないとポインタを持てない?
byref(obj) -> cparam-object
C コードにおける '&obj' に似ていますが,オブジェクトを C 関数呼び出しのパラメタとして渡すためにしか使えません.
pointer(obj) -> ctypes instance
C における '&obj' と同じです. 'byref(obj)' とは異なり,'obj' へのポインタとして振舞う新たな ctypes オブジェクトを生成します.
らしい。
>>> byref(10)
Traceback (most recent call last):
File "", line 1, in
TypeError: byref() argument must be a ctypes instance, not 'int'
>>> pointer(10)
Traceback (most recent call last):
File "", line 1, in
File "/usr/lib/python2.5/ctypes/__init__.py", line 310, in pointer
return POINTER(type(inst))(inst)
File "/usr/lib/python2.5/ctypes/__init__.py", line 254, in POINTER
{'_type_': cls})
TypeError: _type_ must have storage info
やっぱり、Pythonの整数型はポインタを持てない
>>> byref(c_int(10))
>>> pointer(c_int(10))
c_int型はポインタを持てる
となると、
>>> t = c_int()
>>> t
c_long(0)
>>> libc.time(byref(t))
1215875875
>>> t
c_long(1215875875)
>>>
お、予想通り。
ところで、文字列。
>>> s="aaa"
>>> libc.strcmp(s, "aaa")
0
よしよし。
Cでは文字列はchar*型だよ(え?const char*だって?今はめんどいので無視)。
>>> libc.strcmp(s, c_char_p("aaa"))
0
ところで、pythonでは文字列型は変更不能だった。
>>> s[1]="b"
Traceback (most recent call last):
File "", line 1, in
TypeError: 'str' object does not support item assignment
じゃあ、こうするとどうなる?
>>> libc.strcpy(s, "abc")
-1208827276
>>> s
'abc'
すげー。できてる。
調子に乗ってみた。
>>> libc.strcpy(s, "abcde")
-1208827276
>>> s
'abc'
……なんかやっちゃいけないことしちゃったっぽい。
>>> libc.strcpy(s, "z"*1000)
-1208827276
>>> s
セグメンテーション違反です
結論:文字列のデータ自体はいじれる。
けど、強引にメモリ上の値を書き換えているに過ぎない。
(てか、早い話がバッファオーバーフロー?)
配列を知る必要があるような気がする。
ctype * num -> array class
'ctype' を正の整数で乗算すると, 'Array' のサブクラスを生成します.このサブクラスのインスタンスは 'ctype' のインスタンスを 'num'個保持している配列です
>>> i10 = c_int*10
>>> i10
ここで、i100は配列ではなく、配列を作るクラスであることに注意。
>>> a = i10()
>>> a
中身どーやってみるんだ?
ふつーに考えると。
>>> a[0]
0
>>> a[1]
0
あー、めんどくさい。
>>> a[0:len(a)]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
配列は
・lenが使える
・添字やスライスも使える
↓これもOKだった。
>>> list(a)
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
>>> tuple(a)
(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
当然appendはない
>>> a.append(1)
Traceback (most recent call last):
File "", line 1, in
AttributeError: 'c_long_Array_10' object has no attribute 'append'
代入する。
>>> a[0]=1
>>> a[1]=c_int(1)
>>> list(a)
[1, 1, 0, 0, 0, 0, 0, 0, 0, 0]
普通に数字入れても、c_int型で入れてもどっちでもいいらしい。
型が違うと入れられない。
>>> a[0]=0.1
Traceback (most recent call last):
File "", line 1, in
TypeError: int expected instead of float instance
>>> a[0]=c_float(0.1)
Traceback (most recent call last):
File "", line 1, in
TypeError: incompatible types, c_float instance instead of c_long instance
初期値をつけて配列をつくる。
>>> list(i10(1))
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
>>> list(i10(1,2))
[1, 2, 0, 0, 0, 0, 0, 0, 0, 0]
リストやタプルを初期値にしても、思ったようになってくれない
>>> list(i10([1,2]))
Traceback (most recent call last):
File "", line 1, in
TypeError: int expected instead of list instance
>>> list(i10((1,2)))
Traceback (most recent call last):
File "", line 1, in
TypeError: int expected instead of tuple instance
forなりなんなりで初期化せなしゃーないのかな。
簡単にする方法が分からなかった。
疲れたので今日はここまで。
これからもやるのかは分からん。
python ctypes使ってみた。 More ログイン