在Python中转换结构体

1 投票
1 回答
4395 浏览
提问于 2025-04-28 18:19

我正在使用ctypes从一个外部数据库读取一些数据。

这些数据是以结构体的形式写的。问题是,接收到的数据可能会有不同的结果。为了更好地理解,我创建了两个结构体:

class BEAM(Structure):
    _fields_ = [
        ('NR', c_ulong),
        ("NODE1", c_ulong),
        ("NODE2", c_ulong),
        ("NP", c_ulong),
        ("DL", c_float),
        ("foo", c_ulong),
        ("foobar", c_ulong),
        ("bar", c_ulong),
        ("barfoo", c_ulong)
    ]

class DUMMY(Structure):
    _fields_ = [
        ('ID', c_ulong),
        ("NODE1", c_ulong),
        ("NODE2", c_ulong),
        ("NP", c_ulong),
        ("DL", c_ulong),
        ("foo", c_ulong),
        ("foobar", c_ulong),
        ("bar", c_ulong),
        ("barfoo", c_ulong)
    ]

这两个结构体的区别在于“DL”中的u_long类型……在DUMMY中是u_long,而在BEAM中是u_float。

从数据库读取后,我得到的DL = 1056964624,但在浮点数中应该是0.5。

我的问题是,如何将DUMMY转换成BEAM。

我尝试过 BEAMRecord = cast(Record, POINTER(BEAMRecord)),但出现了一个错误,叫做 TypeError: must be a ctypes type。

这是我的代码:

'''
Structure for DataLength
'''
class Len(Structure):
    _fields_ = [
        ('buffer', c_int)
    ]


SLNRecord = element.SLN()
BEAMRecord = element.BEAM()

Record = element.DUMMY()
RecLen = Len()

sofistik = cdll.LoadLibrary("cdb_w30_x64.dll")

py_sof_cdb_init = sofistik.sof_cdb_init
py_sof_cdb_close = sofistik.sof_cdb_close
py_sof_cdb_get = sofistik.sof_cdb_get

py_sof_cdb_get.restype = c_int

Index = py_sof_cdb_init("system.cdb", 99)

pos = c_int(0)

while True:
    RecLen.buffer = sizeof(Record)

    ie = py_sof_cdb_get(Index, 100, 0, byref(Record), byref(RecLen), pos)

    pos.value += 1

    if ie > 1:
        break

    if Record.ID > 0:
        BEAMRecord = cast(Record, POINTER(BEAMRecord))
        print BEAMRecord

py_sof_cdb_close(0)

exit()

谢谢你的帮助。


解决方案:

通过阅读 这个帖子,我修改了@Mr Temp的问题。

我创建了一个 BEAMRecordPointer = POINTER(element.BEAM),然后用 BEAMRecord = cast(Record, POINTER(BEAMRecord)),我重写成 BAR = cast(byref(Record), BEAMRecordPointer).contents,所以解决方案看起来是这样的:

if Record.ID > 0:
        BAR = cast(byref(Record), BEAMRecordPointer).contents
        print BAR

我这样做错了吗?


更新 1

@eryksun 对cast()函数有一个非常好的简写方式。谢谢你。

暂无标签

1 个回答

3

你可以把这个结构加载到一个 Union 里,然后根据需要来访问它:

from ctypes import *

class BEAM(Structure):
    _fields_ = [('NR', c_ulong),
                ("NODE1", c_ulong),
                ("NODE2", c_ulong),
                ("NP", c_ulong),
                ("DL", c_float),
                ("foo", c_ulong),
                ("foobar", c_ulong),
                ("bar", c_ulong),
                ("barfoo", c_ulong)]

class DUMMY(Structure):
    _fields_ = [('ID', c_ulong),
                ("NODE1", c_ulong),
                ("NODE2", c_ulong),
                ("NP", c_ulong),
                ("DL", c_ulong),
                ("foo", c_ulong),
                ("foobar", c_ulong),
                ("bar", c_ulong),
                ("barfoo", c_ulong)]

class Both(Union):
    _fields_ = [('Beam',BEAM),('Dummy',DUMMY)]

x = Both()
x.Dummy.DL = 1056964624
print(x.Beam.DL)

输出结果:

0.5000009536743164

或者更简单一点:

from ctypes import *

class DL(Union):
    _fields_ = [('DUMMY',c_ulong),('BEAM',c_float)]

class Hybrid(Structure):
    _fields_ = [('NR', c_ulong),
                ("NODE1", c_ulong),
                ("NODE2", c_ulong),
                ("NP", c_ulong),
                ("DL", DL),
                ("foo", c_ulong),
                ("foobar", c_ulong),
                ("bar", c_ulong),
                ("barfoo", c_ulong)]

x = Hybrid()
x.DL.DUMMY = 1056964624
print(x.DL.BEAM)

(输出结果是一样的)

撰写回答