14.14.1.15 型変換

たいていの場合、ctypesは厳密な型チェックを行います。これが意味するのは、 関数のargtypesリスト内に、もしくは、構造体定義におけるメンバーフィールドの型として POINTER(c_int)がある場合、厳密に同じ型のインスタンスだけを 受け取るということです。このルールにはctypesが他のオブジェクトを 受け取る場合に例外がいくつかあります。例えば、ポインタ型の代わりに 互換性のある配列インスタンスを渡すことができます。このように、 POINTER(c_int)に対して、ctypesはc_intの配列を受け取ります:

>>> class Bar(Structure):
...     _fields_ = [("count", c_int), ("values", POINTER(c_int))]
...
>>> bar = Bar()
>>> bar.values = (c_int * 3)(1, 2, 3)
>>> bar.count = 3
>>> for i in range(bar.count):
...     print bar.values[i]
...
1
2
3
>>>

POINTER型フィールドをNULLに設定するために、Noneを代入してもよい:

>>> bar.values = None
>>>

XXX list other conversions...

時には、非互換な型のインスタンスであることもあります。Cでは、 ある型を他の型へキャストすることができます。ctypesは 同じやり方で使えるcast関数を提供しています。上で定義したBar構造体は POINTER(c_int)ポインタまたはc_int配列をvaluesフィールドに 対して受け取り、他の型のインスタンスは受け取りません:

>>> bar.values = (c_byte * 4)()
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: incompatible types, c_byte_Array_4 instance instead of LP_c_long instance
>>>

このような場合には、cast関数が便利です。

cast関数はctypesインスタンスを異なるctypesデータ型を指すポインタへ キャストするために使えます。castは二つのパラメータ、 ある種のポインタかそのポインタへ変換できるctypesオブジェクトと、 ctypesポインタ型を取ります。そして、第二引数のインスタンスを返します。 このインスタンスは第一引数と同じメモリブロックを参照しています:

>>> a = (c_byte * 4)()
>>> cast(a, POINTER(c_int))
<ctypes.LP_c_long object at ...>
>>>

したがって、castBar構造体のvaluesフィールドへ代入するために 使うことができます:

>>> bar = Bar()
>>> bar.values = cast((c_byte * 4)(), POINTER(c_int))
>>> print bar.values[0]
0
>>>

ご意見やご指摘をお寄せになりたい方は、 このドキュメントについて... をご覧ください。