ctypes構造体(Structure)汎用フォーマット出力印刷等
背景
実装およびコード検証
1.出力構造体情報のフォーマット
ベースクラスの定義
次に、クラス
構造体のフィールドセット
ここで、
次に、書き込みコードテストの実装効果
テストの発見効果は悪くなく、出力結果は比較的友好的で、詳細はコード注釈を参照してください.
ネストされた構造体のテストコード:
ネストされた複雑な構造体は依然として正常に出力できることが分かった、|゚ρ゚)ノ哦!work over~~~
2.メモリアドレス操作、文字列メモリブロック出力
構造体を直接メモリカードアドレスに変換し、そのデータを出力し、コードを以下のように実現する.
テストコード:
出力結果:
3.メモリアドレス操作、バイナリフォーマット出力
指定したメモリブロックのデータに対して、統一的なデータデータ型で出力を解析し、一般的に純文字列またはその他の簡単なタイプの配列を出力するために使用され、実装コードは以下の通りである.
テストコードは次のとおりです.
出力結果は次のとおりです.
出力結果のデータは
完全なコードとテスト例
python
とc\c++
を混合してプログラミングする場合、私たちは通常python
のctypes
スキームを使用します.この場合、符号化の過程でc
の構造体struct
と付き合うことは避けられません.符号化プロセス、特にデバッグでは、構造体情報を容易に表示またはログ印刷する必要がある場合があります.c
の方法で構造体メンバー一人一人が手動で出力を符号化すると、複雑で手間がかかります.そのため、構造体オブジェクト情報を容易に調べるために、一般的な
の機能を実現する必要があります.本稿では、上記の要件に基づいて実装されるスキームの1つである.ベースクラスを定義し、構造体メンバー変数のフォーマット出力を実現する.ここで、dump_dict
は構造体を辞書に変換し、__str__
はオブジェクトの文字列タイプ変換を実現し、show
は`pprint`を使用して辞書データ結果を出力する.実装およびコード検証
1.出力構造体情報のフォーマット
ベースクラスの定義
#
class myStructure(Structure):
pass
次に、クラス
myStructure
でデルのニーズを実現します.dump_dict
は次のとおりです.#
def dump_dict(self):
info = {}
# _fields_
# ,
#
for k, v in self._fields_:
av = getattr(self, k)
if type(v) == type(Structure):
av = av.dump_dict()
elif type(v) == type(Array):
av = cast(av, c_char_p).value.decode()
else:
pass
info[k] = av
return info
構造体のフィールドセット
_fields_
を巡回し、getattr
を使用して対応するメンバー変数の属性値情報を取得し、その情報に基づいて出力をフォーマットします.ここでは辞書タイプにフォーマットします.ここで、
および
タイプについては特別な処理が必要であり、
は再帰的に呼び出す必要があり、
は文字列で出力される(私の実際の使用では配列は文字列であるため).ここで、
__str__
およびshow
は、それぞれ関数dump_dict
に基づいて、必要な機能に再カプセル化すればよい.#
def __str__(self):
info = self.dump_dict()
return repr(info)
#
def show(self):
from pprint import pprint
pprint(self.dump_dict())
次に、書き込みコードテストの実装効果
#
class ST_ADDR(myStructure):
_fields_ = [
('Addr', c_char*32),
('Port', c_int),
]
# ST_ADDR
addr = ST_ADDR()
# :{'Addr': '', 'Port': 0}
addr.show()
# :{'Addr': '', 'Port': 0}
print(addr)
#
addr.Addr = b'127.0.0.1'
addr.Port = 8080
# :{'Addr': '127.0.0.1', 'Port': 8080}
addr.show()
テストの発見効果は悪くなく、出力結果は比較的友好的で、詳細はコード注釈を参照してください.
ネストされた構造体のテストコード:
#
class ST_ADDR(myStructure):
_fields_ = [
('Addr', c_char*32),
('Port', c_int),
]
# HOOK
class ST_HOOK(myStructure):
_fields_ = [
('UserID', c_uint), # ID
('HostName', c_char * 64), #
('QueueName', c_char * 64), #
('QueueType', c_uint), #
]
# ST_PACKHEAD:
class ST_PACKHEAD(myStructure):
_fields_ = [
('RequestType', c_uint), # ( )
('addr', ST_ADDR), # (6 )
('hook', ST_HOOK), # ( )
('userdata', c_uint), # ( )
('ParmBits',c_ubyte*64), #
]
def main():
# ST_ADDR
addr = ST_ADDR()
# :{'Addr': '', 'Port': 0}
addr.show()
# :{'Addr': '', 'Port': 0}
print(addr)
#
addr.Addr = b'127.0.0.1'
addr.Port = 8080
# :{'Addr': '127.0.0.1', 'Port': 8080}
addr.show()
# ST_HOOK
hook = ST_HOOK()
# :{'HostName': '', 'QueueName': '', 'QueueType': 0, 'UserID': 0}
hook.show()
# :{'UserID': 0, 'HostName': '', 'QueueName': '', 'QueueType': 0}
print(hook)
#
hook.UserID = 578
hook.HostName = b'127.0.0.1'
hook.QueueName = b'q_req'
hook.QueueType = 5205
# :{'UserID': 578, 'HostName': '127.0.0.1', 'QueueName': 'q_req', 'QueueType': 5205}
print(hook)
# ST_PACKHEAD ,
head = ST_PACKHEAD()
# :
# 'ParmBits': '',
# 'RequestType': 0,
# 'addr': {'Addr': '', 'Port': 0},
# 'hook': {'HostName': '', 'QueueName': '', 'QueueType': 0, 'UserID': 0},
# 'userdata': 0}
head.show()
# :{'RequestType': 0, 'addr': {'Addr': '', 'Port': 0}, 'hook': {'UserID': 0, 'HostName': '', 'QueueName': '', 'QueueType': 0}, 'userdata': 0, 'ParmBits': ''}
print(head)
#
head.RequestType = 404456
head.userdata = 1234
head.addr.Addr = b'127.0.0.1'
head.hook = hook
# :
# {'ParmBits': '',
# 'RequestType': 404456,
# 'addr': {'Addr': '127.0.0.1', 'Port': 0},
# 'hook': {'HostName': '127.0.0.1',
# 'QueueName': 'q_req',
# 'QueueType': 5205,
# 'UserID': 578},
# 'userdata': 1234}
head.show()
ネストされた複雑な構造体は依然として正常に出力できることが分かった、|゚ρ゚)ノ哦!work over~~~
2.メモリアドレス操作、文字列メモリブロック出力
構造体を直接メモリカードアドレスに変換し、そのデータを出力し、コードを以下のように実現する.
#
def string(self):
return string_at(addressof(self), sizeof(self))
テストコード:
# ST_ADDR
addr = ST_ADDR()
addr.Addr = b'127.0.0.1'
addr.Port = 8080
print(addr.string())
出力結果:
b'127.0.0.1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x90\x1f\x00\x00'
3.メモリアドレス操作、バイナリフォーマット出力
指定したメモリブロックのデータに対して、統一的なデータデータ型で出力を解析し、一般的に純文字列またはその他の簡単なタイプの配列を出力するために使用され、実装コードは以下の通りである.
#
# ctp : , ctypes , c_char, c_int
# row_num :
# full : , ctp , ctp c_char
def show_meminfo(self, ctp=c_char, row_num = 8, full = False):
import struct
# # , char
if full and sizeof(self)%sizeof(ctp):
ctp = c_char
block = int(sizeof(self)/sizeof(ctp))
addr = string_at(addressof(self), sizeof(self))
for i in range(block):
v = struct.unpack(ctp._type_, addr[i*sizeof(ctp):(i+1)*sizeof(ctp)])
pend = '
' if (i+1)%row_num==0 else ' '
print(repr(v[0]), end=pend)
print()
テストコードは次のとおりです.
class ST_DATA(myStructure):
_fields_ = [
('day1', c_int*3),
('day2', c_int * 4),
('day3', c_int * 5),
('day4', c_int * 6),
('day5', c_int * 7),
]
def main():
# ST_DATA
data = ST_DATA()
data.day1 = (c_int*3)(11, 12, 13)
data.day2 = (c_int * 4)(21, 22, 23, 24)
data.day3 = (c_int * 5)(31, 32, 33, 34, 35)
data.day4 = (c_int * 6)(41, 42, 43, 44, 45, 46)
data.day5 = (c_int * 7)(51, 52, 53, 54, 55, 56, 57)
data.show_meminfo(c_int, 4)
出力結果は次のとおりです.
11 12 13 21
22 23 24 31
32 33 34 35
41 42 43 44
45 46 51 52
53 54 55 56
57
出力結果のデータは
c_int
ユニットで解析され、出力が整列していることがわかります.完全なコードとテスト例
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from ctypes import *
#
class myStructure(Structure):
#
def dump_dict(self):
info = {}
# _fields_
# ,
#
for k, v in self._fields_:
av = getattr(self, k)
if type(v) == type(Structure):
av = av.dump_dict()
elif type(v) == type(Array):
av = cast(av, c_char_p).value.decode()
else:
pass
info[k] = av
return info
#
def __str__(self):
info = self.dump_dict()
return repr(info)
#
def show(self):
from pprint import pprint
pprint(self.dump_dict())
#
class ST_ADDR(myStructure):
_fields_ = [
('Addr', c_char*32),
('Port', c_int),
]
# HOOK
class ST_HOOK(myStructure):
_fields_ = [
('UserID', c_uint), # ID
('HostName', c_char * 64), #
('QueueName', c_char * 64), #
('QueueType', c_uint), #
]
# ST_PACKHEAD:
class ST_PACKHEAD(myStructure):
_fields_ = [
('RequestType', c_uint), # ( )
('addr', ST_ADDR), # (6 )
('hook', ST_HOOK), # ( )
('userdata', c_uint), # ( )
('ParmBits',c_ubyte*64), #
]
def main():
# ST_ADDR
addr = ST_ADDR()
# :{'Addr': '', 'Port': 0}
addr.show()
# :{'Addr': '', 'Port': 0}
print(addr)
#
addr.Addr = b'127.0.0.1'
addr.Port = 8080
# :{'Addr': '127.0.0.1', 'Port': 8080}
addr.show()
# ST_HOOK
hook = ST_HOOK()
# :{'HostName': '', 'QueueName': '', 'QueueType': 0, 'UserID': 0}
hook.show()
# :{'UserID': 0, 'HostName': '', 'QueueName': '', 'QueueType': 0}
print(hook)
#
hook.UserID = 578
hook.HostName = b'127.0.0.1'
hook.QueueName = b'q_req'
hook.QueueType = 5205
# :{'UserID': 578, 'HostName': '127.0.0.1', 'QueueName': 'q_req', 'QueueType': 5205}
print(hook)
# ST_PACKHEAD ,
head = ST_PACKHEAD()
# :
# 'ParmBits': '',
# 'RequestType': 0,
# 'addr': {'Addr': '', 'Port': 0},
# 'hook': {'HostName': '', 'QueueName': '', 'QueueType': 0, 'UserID': 0},
# 'userdata': 0}
head.show()
# :{'RequestType': 0, 'addr': {'Addr': '', 'Port': 0}, 'hook': {'UserID': 0, 'HostName': '', 'QueueName': '', 'QueueType': 0}, 'userdata': 0, 'ParmBits': ''}
print(head)
#
head.RequestType = 404456
head.userdata = 1234
head.addr.Addr = b'127.0.0.1'
head.hook = hook
# :
# {'ParmBits': '',
# 'RequestType': 404456,
# 'addr': {'Addr': '127.0.0.1', 'Port': 0},
# 'hook': {'HostName': '127.0.0.1',
# 'QueueName': 'q_req',
# 'QueueType': 5205,
# 'UserID': 578},
# 'userdata': 1234}
head.show()
if __name__ == '__main__':
main()