"struct" --- 将字节串解读为打包的二进制数据
*******************************************

**源代码：** Lib/struct.py

======================================================================

This module performs conversions between Python values and C structs
represented as Python "bytes" objects.  This can be used in handling
binary data stored in files or from network connections, among other
sources.  It uses 格式字符串 as compact descriptions of the layout of
the C structs and the intended conversion to/from Python values.

注解:

  By default, the result of packing a given C struct includes pad
  bytes in order to maintain proper alignment for the C types
  involved; similarly, alignment is taken into account when unpacking.
  This behavior is chosen so that the bytes of a packed struct
  correspond exactly to the layout in memory of the corresponding C
  struct.  To handle platform-independent data formats or omit
  implicit pad bytes, use "standard" size and alignment instead of
  "native" size and alignment: see 字节顺序，大小和对齐方式 for
  details.

某些 "struct" 的函数（以及 "Struct" 的方法）接受一个 *buffer* 参数。
这将指向实现了 缓冲协议 并提供只读或是可读写缓冲的对象。 用于此目的的
最常见类型为 "bytes" 和 "bytearray"，但许多其他可被视为字节数组的类型
也实现了缓冲协议，因此它们无需额外从 "bytes" 对象复制即可被读取或填充
。


函数和异常
==========

此模块定义了下列异常和函数：

exception struct.error

   会在多种场合下被引发的异常；其参数为一个描述错误信息的字符串。

struct.pack(format, v1, v2, ...)

   返回一个 bytes 对象，其中包含根据格式字符串 *format* 打包的值 *v1*,
   *v2*, ... 参数个数必须与格式字符串所要求的值完全匹配。

struct.pack_into(format, buffer, offset, v1, v2, ...)

   根据格式字符串 *format* 打包 *v1*, *v2*, ... 等值并将打包的字节串写
   入可写缓冲区 *buffer* 从 *offset* 开始的位置。 请注意 *offset* 是必
   需的参数。

struct.unpack(format, buffer)

   根据格式字符串 *format* 从缓冲区 *buffer* 解包（假定是由
   "pack(format, ...)" 打包）。 结果为一个元组，即使其只包含一个条目。
   缓冲区的字节大小必须匹配格式所要求的大小，如 "calcsize()" 所示。

struct.unpack_from(format, /, buffer, offset=0)

   对 *buffer* 从位置 *offset* 开始根据格式字符串 *format* 进行解包。
   结果为一个元组，即使其中只包含一个条目。 缓冲区的字节大小从位置
   *offset* 开始必须至少为 "calcsize()" 显示的格式所要求的大小。

struct.iter_unpack(format, buffer)

   Iteratively unpack from the buffer *buffer* according to the format
   string *format*.  This function returns an iterator which will read
   equally-sized chunks from the buffer until all its contents have
   been consumed.  The buffer's size in bytes must be a multiple of
   the size required by the format, as reflected by "calcsize()".

   每次迭代将产生一个如格式字符串所指定的元组。

   3.4 新版功能.

struct.calcsize(format)

   返回与格式字符串 *format* 相对应的结构的大小（亦即 "pack(format,
   ...)" 所产生的字节串对象的大小）。


格式字符串
==========

Format strings are the mechanism used to specify the expected layout
when packing and unpacking data.  They are built up from 格式字符,
which specify the type of data being packed/unpacked.  In addition,
there are special characters for controlling the 字节顺序，大小和对齐
方式.


字节顺序，大小和对齐方式
------------------------

By default, C types are represented in the machine's native format and
byte order, and properly aligned by skipping pad bytes if necessary
(according to the rules used by the C compiler).

或者，根据下表，格式字符串的第一个字符可用于指示打包数据的字节顺序，大
小和对齐方式：

+-------------+--------------------------+------------+-------------+
| 字符        | 字节顺序                 | 大小       | 对齐方式    |
|=============|==========================|============|=============|
| "@"         | 按原字节                 | 按原字节   | 按原字节    |
+-------------+--------------------------+------------+-------------+
| "="         | 按原字节                 | 标准       | 无          |
+-------------+--------------------------+------------+-------------+
| "<"         | 小端                     | 标准       | 无          |
+-------------+--------------------------+------------+-------------+
| ">"         | 大端                     | 标准       | 无          |
+-------------+--------------------------+------------+-------------+
| "!"         | 网络（=大端）            | 标准       | 无          |
+-------------+--------------------------+------------+-------------+

如果第一个字符不是其中之一，则假定为 "'@'" 。

Native byte order is big-endian or little-endian, depending on the
host system. For example, Intel x86 and AMD64 (x86-64) are little-
endian; Motorola 68000 and PowerPC G5 are big-endian; ARM and Intel
Itanium feature switchable endianness (bi-endian). Use "sys.byteorder"
to check the endianness of your system.

本机大小和对齐方式是使用 C 编译器的 "sizeof" 表达式来确定的。 这总是会
与本机字节顺序相绑定。

标准大小仅取决于格式字符；请参阅 格式字符 部分中的表格。

请注意 "'@'" 和 "'='" 之间的区别：两个都使用本机字节顺序，但后者的大小
和对齐方式是标准化的。

形式 "'!'" 代表网络字节顺序总是使用在 IETF RFC 1700 中所定义的大端序。

没有什么方式能指定非本机字节顺序（强制字节对调）；请正确选择使用 "'<'"
或 "'>'"。

注释：

1. 填充只会在连续结构成员之间自动添加。 填充不会添加到已编码结构的开头
   和末尾。

2. 当使用非本机大小和对齐方式即 '<', '>', '=', and '!' 时不会添加任何
   填充。

3. 要将结构的末尾对齐到符合特定类型的对齐要求，请以该类型代码加重复计
   数的零作为格式结束。 参见 例子。


格式字符
--------

格式字符具有以下含义；C 和 Python 值之间的按其指定类型的转换应当是相当
明显的。 ‘标准大小’列是指当使用标准大小时以字节表示的已打包值大小；也
就是当格式字符串以 "'<'", "'>'", "'!'" 或 "'='" 之一开头的情况。 当使
用本机大小时，已打包值的大小取决于具体的平台。

+----------+----------------------------+----------------------+------------------+--------------+
| 格式     | C 类型                     | Python 类型          | 标准大小         | 备注         |
|==========|============================|======================|==================|==============|
| "x"      | 填充字节                   | 无                   |                  |              |
+----------+----------------------------+----------------------+------------------+--------------+
| "c"      | "char"                     | 长度为 1 的字节串    | 1                |              |
+----------+----------------------------+----------------------+------------------+--------------+
| "b"      | "signed char"              | integer              | 1                | (1), (2)     |
+----------+----------------------------+----------------------+------------------+--------------+
| "B"      | "unsigned char"            | integer              | 1                | (2)          |
+----------+----------------------------+----------------------+------------------+--------------+
| "?"      | "_Bool"                    | bool                 | 1                | (1)          |
+----------+----------------------------+----------------------+------------------+--------------+
| "h"      | "short"                    | integer              | 2                | (2)          |
+----------+----------------------------+----------------------+------------------+--------------+
| "H"      | "unsigned short"           | integer              | 2                | (2)          |
+----------+----------------------------+----------------------+------------------+--------------+
| "i"      | "int"                      | integer              | 4                | (2)          |
+----------+----------------------------+----------------------+------------------+--------------+
| "I"      | "unsigned int"             | integer              | 4                | (2)          |
+----------+----------------------------+----------------------+------------------+--------------+
| "l"      | "long"                     | integer              | 4                | (2)          |
+----------+----------------------------+----------------------+------------------+--------------+
| "L"      | "unsigned long"            | integer              | 4                | (2)          |
+----------+----------------------------+----------------------+------------------+--------------+
| "q"      | "long long"                | integer              | 8                | (2)          |
+----------+----------------------------+----------------------+------------------+--------------+
| "Q"      | "unsigned long long"       | integer              | 8                | (2)          |
+----------+----------------------------+----------------------+------------------+--------------+
| "n"      | "ssize_t"                  | integer              |                  | (3)          |
+----------+----------------------------+----------------------+------------------+--------------+
| "N"      | "size_t"                   | integer              |                  | (3)          |
+----------+----------------------------+----------------------+------------------+--------------+
| "e"      | (6)                        | float                | 2                | (4)          |
+----------+----------------------------+----------------------+------------------+--------------+
| "f"      | "float"                    | float                | 4                | (4)          |
+----------+----------------------------+----------------------+------------------+--------------+
| "d"      | "double"                   | float                | 8                | (4)          |
+----------+----------------------------+----------------------+------------------+--------------+
| "s"      | "char[]"                   | 字节串               |                  |              |
+----------+----------------------------+----------------------+------------------+--------------+
| "p"      | "char[]"                   | 字节串               |                  |              |
+----------+----------------------------+----------------------+------------------+--------------+
| "P"      | "void *"                   | integer              |                  | (5)          |
+----------+----------------------------+----------------------+------------------+--------------+

在 3.3 版更改: 增加了对 "'n'" 和 "'N'" 格式的支持

在 3.6 版更改: 添加了对 "'e'" 格式的支持。

注释：

1. The "'?'" conversion code corresponds to the "_Bool" type defined
   by C99. If this type is not available, it is simulated using a
   "char". In standard mode, it is always represented by one byte.

2. 当尝试使用任何整数转换码打包一个非整数时，如果该非整数具有
   "__index__()" 方法，则会在打包之前调用该方法将参数转换为一个整数。

   在 3.2 版更改: 增加了针对非整数使用 "__index__()" 方法的特性。

3. "'n'" 和 "'N'" 转换码仅对本机大小可用（选择为默认或使用 "'@'" 字节
   顺序字符）。 对于标准大小，你可以使用适合你的应用的任何其他整数格式
   。

4. 对于 "'f'", "'d'" 和 "'e'" 转换码，打包表示形式将使用 IEEE 754
   binary32, binary64 或 binary16 格式 (分别对应于 "'f'", "'d'" 或
   "'e'")，无论平台使用何种浮点格式。

5. "'P'" 格式字符仅对本机字节顺序可用（选择为默认或使用 "'@'" 字节顺序
   字符）。 字节顺序字符 "'='" 选择使用基于主机系统的小端或大端排序。
   struct 模块不会将其解读为本机排序，因此 "'P'" 格式将不可用。

6. IEEE 754 binary16 "半精度" 类型是在 IEEE 754 标准 的 2008 修订版中
   引入的。 它包含一个符号位，5 个指数位和 11 个精度位（明确存储 10 位
   ），可以完全精确地表示大致范围在 "6.1e-05" 和 "6.5e+04" 之间的数字
   。 此类型并不被 C 编译器广泛支持：在一台典型的机器上，可以使用
   unsigned short 进行存储，但不会被用于数学运算。 请参阅维基百科页面
   half-precision floating-point format 了解详情。

格式字符之前可以带有整数重复计数。 例如，格式字符串 "'4h'" 的含义与
"'hhhh'" 完全相同。

格式之间的空白字符会被忽略；但是计数及其格式字符中不可有空白字符。

For the "'s'" format character, the count is interpreted as the length
of the bytes, not a repeat count like for the other format characters;
for example, "'10s'" means a single 10-byte string, while "'10c'"
means 10 characters. If a count is not given, it defaults to 1.  For
packing, the string is truncated or padded with null bytes as
appropriate to make it fit. For unpacking, the resulting bytes object
always has exactly the specified number of bytes.  As a special case,
"'0s'" means a single, empty string (while "'0c'" means 0 characters).

当使用某一种整数格式 ("'b'", "'B'", "'h'", "'H'", "'i'", "'I'", "'l'",
"'L'", "'q'", "'Q'") 打包值 "x" 时，如果 "x" 在该格式的有效范围之外则
将引发 "struct.error"。

在 3.1 版更改: 在之前版本中，某些整数格式包装了超范围的值并会引发
"DeprecationWarning" 而不是 "struct.error"。

"'p'" 格式字符用于编码“Pascal 字符串”，即存储在由计数指定的 *固定长度
字节* 中的可变长度短字符串。 所存储的第一个字节为字符串长度或 255 中的
较小值。 之后是字符串对应的字节。 如果传入 "pack()" 的字符串过长（超过
计数值减 1），则只有字符串前 "count-1" 个字节会被存储。 如果字符串短于
"count-1"，则会填充空字节以使得恰好使用了 count 个字节。 请注意对于
"unpack()"，"'p'" 格式字符会消耗 "count" 个字节，但返回的字符串永远不
会包含超过 255 个字节。

对于 "'?'" 格式字符，返回值为 "True" 或 "False"。 在打包时将会使用参数
对象的逻辑值。 以本机或标准 bool 类型表示的 0 或 1 将被打包，任何非零
值在解包时将为 "True"。


例子
----

注解:

  All examples assume a native byte order, size, and alignment with a
  big-endian machine.

A basic example of packing/unpacking three integers:

   >>> from struct import *
   >>> pack('hhl', 1, 2, 3)
   b'\x00\x01\x00\x02\x00\x00\x00\x03'
   >>> unpack('hhl', b'\x00\x01\x00\x02\x00\x00\x00\x03')
   (1, 2, 3)
   >>> calcsize('hhl')
   8

解包的字段可通过将它们赋值给变量或将结果包装为一个具名元组来命名:

   >>> record = b'raymond   \x32\x12\x08\x01\x08'
   >>> name, serialnum, school, gradelevel = unpack('<10sHHb', record)

   >>> from collections import namedtuple
   >>> Student = namedtuple('Student', 'name serialnum school gradelevel')
   >>> Student._make(unpack('<10sHHb', record))
   Student(name=b'raymond   ', serialnum=4658, school=264, gradelevel=8)

The ordering of format characters may have an impact on size since the
padding needed to satisfy alignment requirements is different:

   >>> pack('ci', b'*', 0x12131415)
   b'*\x00\x00\x00\x12\x13\x14\x15'
   >>> pack('ic', 0x12131415, b'*')
   b'\x12\x13\x14\x15*'
   >>> calcsize('ci')
   8
   >>> calcsize('ic')
   5

The following format "'llh0l'" specifies two pad bytes at the end,
assuming longs are aligned on 4-byte boundaries:

   >>> pack('llh0l', 1, 2, 3)
   b'\x00\x00\x00\x01\x00\x00\x00\x02\x00\x03\x00\x00'

This only works when native size and alignment are in effect; standard
size and alignment does not enforce any alignment.

参见:

  模块 "array"
     被打包为二进制存储的同质数据。

  "xdrlib" 模块
     Packing and unpacking of XDR data.


类
==

"struct" 模块还定义了以下类型：

class struct.Struct(format)

   Return a new Struct object which writes and reads binary data
   according to the format string *format*.  Creating a Struct object
   once and calling its methods is more efficient than calling the
   "struct" functions with the same format since the format string
   only needs to be compiled once.

   注解:

     传递给 "Struct" 和模块层级函数的已编译版最新格式字符串会被缓存，
     因此只使用少量格式字符串的程序无需担心重用单独的 "Struct" 实例。

   已编译的 Struct 对象支持以下方法和属性：

   pack(v1, v2, ...)

      等价于 "pack()" 函数，使用了已编译的格式。 ("len(result)" 将等于
      "size"。)

   pack_into(buffer, offset, v1, v2, ...)

      等价于 "pack_into()" 函数，使用了已编译的格式。

   unpack(buffer)

      等价于 "unpack()" 函数，使用了已编译的格式。 缓冲区的字节大小必
      须等于 "size"。

   unpack_from(buffer, offset=0)

      等价于 "unpack_from()" 函数，使用了已编译的格式。 缓冲区的字节大
      小从位置 *offset* 开始必须至少为 "size"。

   iter_unpack(buffer)

      等价于 "iter_unpack()" 函数，使用了已编译的格式。 缓冲区的大小必
      须为 "size" 的整数倍。

      3.4 新版功能.

   format

      用于构造此 Struct 对象的格式字符串。

      在 3.7 版更改: 格式字符串类型现在是 "str" 而不再是 "bytes"。

   size

      计算出对应于 "format" 的结构大小（亦即 "pack()" 方法所产生的字节
      串对象的大小）。
