Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/360.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python:结构和数组与ctypes中的类似功能_Python_Arrays_Struct_Ctypes_Binary Data - Fatal编程技术网

Python:结构和数组与ctypes中的类似功能

Python:结构和数组与ctypes中的类似功能,python,arrays,struct,ctypes,binary-data,Python,Arrays,Struct,Ctypes,Binary Data,Python提供了以下三个模块来处理C类型以及如何处理它们: 对于C结构 对于类似于C中的数组 对于C函数,这必然需要处理C的类型系统 虽然ctypes似乎比struct和array更通用、更灵活(其主要任务是“Python的外部函数库”),但当任务是读取二进制数据结构时,这三个模块之间的功能似乎有很大的重叠。例如,如果我想读一个C结构 struct MyStruct { int a; float b; char c[12]; }; 我可以使用struct如下: a

Python提供了以下三个模块来处理C类型以及如何处理它们:

  • 对于C结构
  • 对于类似于C中的数组
  • 对于C函数,这必然需要处理C的类型系统
虽然
ctypes
似乎比
struct
array
更通用、更灵活(其主要任务是“Python的外部函数库”),但当任务是读取二进制数据结构时,这三个模块之间的功能似乎有很大的重叠。例如,如果我想读一个C结构

struct MyStruct {
    int a;
    float b;
    char c[12];
};
我可以使用
struct
如下:

a, b, c = struct.unpack('if12s', b'\x11\0\0\0\x12\x34\x56\x78hello world\0')
print(a, b, c)
# 17 1.7378244361449504e+34 b'hello world\x00'
另一方面,(虽然有点冗长):

(旁白:我确实想知道在这个版本中尾随的
'\0'
到哪里去了…)

在我看来,这似乎违反了《Python禅宗》中的原则:

  • 应该有一种方法,最好只有一种显而易见的方法

  • 那么,对于二进制数据处理的几个类似模块,这种情况是如何出现的呢?是历史原因还是现实原因?(例如,我可以想象完全省略
    struct
    模块,只需添加一个更方便的API来读/写C结构到
    ctypes

    免责声明:这篇文章是基于我对Python stdlib中“分工”的理解,而不是基于事实上可参考的信息

    你的问题源于这样一个事实,“C结构”和“二进制数据”倾向于互换使用,这在实践中是正确的,但在技术意义上是错误的。
    struct
    文档也有误导性:它声称可以在“C结构”上工作,而更好的描述应该是“二进制数据”,其中有一些关于C兼容性的免责声明

    基本上,
    struct
    array
    ctypes
    做不同的事情<代码>结构处理将Python值转换为内存中的二进制格式<代码>数组处理高效存储大量值的问题<代码>ctypes处理C语言(*)。功能上的重叠源于这样一个事实:对于C,“内存中的二进制格式”是本机的,“有效地存储值”是将它们打包到一个类似C的数组中

    您还将注意到,
    struct
    允许您轻松指定endianness,因为它以多种不同的方式处理二进制数据的打包和解包;而在
    ctypes
    中,更难获得非本机字节顺序,因为它使用的是C本机的字节顺序

    如果您的任务是读取二进制数据结构,那么抽象级别将不断增加:

  • 手动拆分字节数组并使用
    int.from_bytes
    等转换部分
  • 使用格式字符串描述数据,并使用
    struct
    一次性解包
  • 使用一个库,比如用逻辑术语声明性地描述结构
  • ctypes
    在这里甚至不需要说明,因为对于这个任务,使用
    ctypes
    几乎需要通过一种不同的编程语言进行往返。事实上,对于你的例子来说,它同样有效是偶然的;它之所以能工作,是因为C语言天生适合表达多种打包二进制数据的方式。但是,例如,如果您的结构是混合endian,则很难在
    ctypes
    中表达。另一个例子是半精度浮点,它没有C等价物(请参阅)

    从这个意义上说,
    ctypes
    使用
    struct
    ,这也是非常合理的——毕竟,“打包和解包二进制数据”是“与C接口”的一个子任务

    另一方面,
    struct
    使用
    ctypes
    :这就像使用
    电子邮件
    库进行字符编码转换一样,因为这是电子邮件库可以完成的任务


    (*)嗯,基本上。更精确的是类似“基于C的环境”,即现代计算机如何在低水平上工作,这是由于以C作为主要系统语言的共同进化。

    尽管这种方式一开始可能并不明显,除非你是荷兰人:-)1。
    \0
    仍然存在,但未打印(选中
    NULL
    终止字符串)。2.它们可能是并行开发的(我记得第一次,ctypes不在Python标准库中)。功能部分重叠。删除一个这样的模块会破坏向后兼容性,因为可能有很多代码依赖于3个模块中的每一个。注意:ctypes使用struct@CristiFati 1。但是,它是在
    struct
    版本中打印的!另外:
    len(c)==12
    len(s.c)==11
    。2.在向Python3的转换过程中,Python做了很多向后不兼容的更改。据我所知,这些“缺点”/冗余正是Python 3.1想要消除的。是的,您是对的,显然在处理字符数组时,当
    \0
    被禁用时,缓冲区解析(对于该字段)就会停止encountered@CristiFati还有:“ctypes使用struct。”你有关于它的参考资料或详细信息吗?这就是我要找的,谢谢!我想让我产生兴趣的是
    struct
    文档中关于“C structs”的术语/重点(第一句话:“此模块执行Python值和C structs[…]之间的转换”),而实际上,正如您所说,它可以处理更多任意的二进制数据。
     class MyStruct(ctypes.Structure):
         _fields_ = [
             ('a', ctypes.c_int),
             ('b', ctypes.c_float),
             ('c', ctypes.c_char * 12)
         ]
     s = MyStruct.from_buffer_copy(b'\x11\0\0\0\x12\x34\x56\x78hello world\0')
     print(s.a, s.b, s.c)
     # 17 1.7378244361449504e+34 b'hello world'