Python bigendian结构中的字符串

Python bigendian结构中的字符串,python,ctypes,endianness,Python,Ctypes,Endianness,我想这样做: from ctypes import * class Packet(BigEndianStructure): _fields_ = [("length", c_ushort), ("session", c_uint), ("command", c_ushort)] class PacketString(BigEndianStructure): _fields_ = [("length", c_ush

我想这样做:

from ctypes import *

class Packet(BigEndianStructure):
    _fields_ = [("length", c_ushort),
                ("session", c_uint),
                ("command", c_ushort)]

class PacketString(BigEndianStructure):
    _fields_ = [("length", c_ushort),
                ("value", c_char_p)]

class InitialPacket(Packet):
    _fields_ = [("time", PacketString)]
initialPacket = InitialPacket()
initialPacket.command = 128
但是,我得到了一个错误,因为c_char_p只能是本机字节顺序。但也许还有其他方法可以让字符串的长度在前面指定。我只是喜欢结构如何易于从套接字读取/写入。以及如何定义字段,然后可以这样使用:

from ctypes import *

class Packet(BigEndianStructure):
    _fields_ = [("length", c_ushort),
                ("session", c_uint),
                ("command", c_ushort)]

class PacketString(BigEndianStructure):
    _fields_ = [("length", c_ushort),
                ("value", c_char_p)]

class InitialPacket(Packet):
    _fields_ = [("time", PacketString)]
initialPacket = InitialPacket()
initialPacket.command = 128
问题是:如何在Bigendian结构中创建可变长度字段?因为Python不允许我使用c_char_p。脚本根本不会运行。这是一个错误:

Traceback (most recent call last):
  File "C:\PKOEmu\test.py", line 8, in <module>
    class PacketString(BigEndianStructure):
  File "C:\Python27\lib\ctypes\_endian.py", line 34, in __setattr__
    fields.append((name, _other_endian(typ)) + rest)
  File "C:\Python27\lib\ctypes\_endian.py", line 24, in _other_endian
    raise TypeError("This type does not support other endian: %s" % typ)
TypeError: This type does not support other endian: <class 'ctypes.c_char_p'>
回溯(最近一次呼叫最后一次):
文件“C:\PKOEmu\test.py”,第8行,在
类PacketString(Bigendian结构):
文件“C:\Python27\lib\ctypes\\ endian.py”,第34行,在\ uu setattr中__
fields.append((名称,_other_endian(类型))+rest)
文件“C:\Python27\lib\ctypes\\ endian.py”,第24行,在\u other\u endian中
raise TypeError(“此类型不支持其他尾端:%s”%typ)
TypeError:此类型不支持其他endian:
此类型:

class PacketString(BigEndianStructure):
    _fields_ = [("length", c_ushort),
                ("value", c_char_p)]
…不做你认为它做的事,甚至忽略了endianness问题。它是一个包含ushort长度的结构,然后是指向内存中其他地方的实际字符串数据的指针

换句话说,它就像这个C结构:

struct PacketString {
    unsigned short length;
    char *value;
};
您要查找的是一个长度前缀字符串,该字符串直接内联在结构中。为此,C结构为:

struct PacketString {
    unsigned short length;
    char value[1];
};
这被称为“结构黑客”。这实际上不是合法的C,但它恰好与每个已知的C89编译器和大多数C99和C++编译器一起工作。见fro详细信息

那么,你能在
ctypes
中做同样的事情吗?嗯,是的,但它没有那么有用:

class PacketString(BigEndianStructure):
    _fields_ = [("length", c_ushort),
                ("value", c_char * 0)]
这可能会变得复杂;有关详细信息,请参见文档中的。特别是,您不能在
p.value
上调用
resize
;您需要计算调整
p
自身大小的大小,然后将
p的类型更改为具有正确类型的字段,然后

这就是为什么医生说:

将可变大小的数据类型与ctypes一起使用的另一种方法是使用Python的动态特性,并在已知所需大小后,根据具体情况(重新)定义数据类型

换言之:

class LocalPacketString(BigEndianStructure):
    _fields_ = [("length", c_ushort),
                ("value", c_char * length)]
ps = LocalPacketString(length, buff)
但是,您可能会注意到,与保持类型独立相比,这并不能真正节省大量工作


总之,struct hack甚至不是有效的C,它也不能很好地映射到
ctypes
ctypes.Structure
不是表示可变长度前缀字符串的好方法。

此类型:

class PacketString(BigEndianStructure):
    _fields_ = [("length", c_ushort),
                ("value", c_char_p)]
…不做你认为它做的事,甚至忽略了endianness问题。它是一个包含ushort长度的结构,然后是指向内存中其他地方的实际字符串数据的指针

换句话说,它就像这个C结构:

struct PacketString {
    unsigned short length;
    char *value;
};
您要查找的是一个长度前缀字符串,该字符串直接内联在结构中。为此,C结构为:

struct PacketString {
    unsigned short length;
    char value[1];
};
这被称为“结构黑客”。这实际上不是合法的C,但它恰好与每个已知的C89编译器和大多数C99和C++编译器一起工作。见fro详细信息

那么,你能在
ctypes
中做同样的事情吗?嗯,是的,但它没有那么有用:

class PacketString(BigEndianStructure):
    _fields_ = [("length", c_ushort),
                ("value", c_char * 0)]
这可能会变得复杂;有关详细信息,请参见文档中的。特别是,您不能在
p.value
上调用
resize
;您需要计算调整
p
自身大小的大小,然后将
p的类型更改为具有正确类型的字段,然后

这就是为什么医生说:

将可变大小的数据类型与ctypes一起使用的另一种方法是使用Python的动态特性,并在已知所需大小后,根据具体情况(重新)定义数据类型

换言之:

class LocalPacketString(BigEndianStructure):
    _fields_ = [("length", c_ushort),
                ("value", c_char * length)]
ps = LocalPacketString(length, buff)
但是,您可能会注意到,与保持类型独立相比,这并不能真正节省大量工作



总之,struct hack甚至不是有效的C,它也不能很好地映射到
ctypes
ctypes.Structure
不是表示可变长度前缀字符串的好方法。

字符没有字节顺序,因为字符只是一个字节。可能错误在于
c_ushort
的字节顺序错误,因此您试图读取1MB的16个字符的字符串?除非您向我们展示相关的代码和输入值以及您得到的实际错误,否则很难知道实际发生了什么。请尝试创建一个@abarnert,实际上这是一个完整的示例。它不会运行。但如果我对
(“value”,c\u char\u p)
行进行注释,它就会出现。这是我得到的错误:
Traceback(最后一次调用):文件“test.py”,第8行,类内PacketString(bigendianstruct):文件“C:\Python27\lib\ctypes\\u endian.py”,第34行,在uuu setattr\uuuu字段中。追加((名称,u other\u endian(typ))+rest)文件“C:\Python27\lib\ctypes\\u endian.py”,第24行,在u other\u endian提高类型错误(“此类型不支持其他端号:%s”%typ)TypeError:此类型不支持其他endian:
好的,您是在尝试将内联字符串粘贴到
PacketString
中,还是在内存中的某个位置粘贴指向字符串的指针?因为您所做的是后者。由于您的内存是本机endian,并且没有其他内存意味着什么,因此无法使用大endian指针ful。正如我所解释的,一个
ushort
加上一个
c\u char\p
并不是一个可变长度的结构;它是一个固定大小的长度,是指向内存中其他地方字符串的固定大小的指针。如果你想要一个内联字符串,它必须是一个数组。嗯,
value
是结构中的最后一个元素,所以这不是问题。但是有还有很多其他问题使得这是一种糟糕的方法。
pack
/
unpack
可能是一个更好的选择,或者更好的是,在
pack
/
unpack
周围包装,可以读取和写入