"struct" --- 將位元組直譯為打包起來的二進位資料
***********************************************

**原始碼：**Lib/struct.py

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

此模組可在 Python 數值與以 Python "bytes" 物件表示的 C 結構之間進行轉
換。簡潔的格式字串描述了與 Python 數值之間預期的轉換。此模組的函式和物
件可用於兩種截然不同的應用程式：與外部來源（檔案或網路連線）的資料交換
，或是 Python 應用程式與 C 層之間的資料傳輸。

備註:

  當未給定前綴字元時會預設為原生模式。它會根據建構 Python 直譯器的平台
  和編譯器來打包或解包資料。打包給定 C 結構的結果包含填充位元組，以維
  持相關 C 型別的正確對齊；同樣地，解包時也會考量對齊。相反地，當在外
  部來源之間傳輸資料時，程式設計師需負責定義位元組順序和元素之間的填充
  。詳情請參見 位元組順序、大小和對齊。

一些 "struct" 函式（和 "Struct" 的方法）接受一個 *buffer* 引數。這是指
實作緩衝協定 (Buffer Protocol) 並提供可讀或可讀寫緩衝區的物件。最常用
於此目的的型別是 "bytes" 和 "bytearray"，但許多其他可以視為位元組陣列
的型別都實作了緩衝區協定，因此它們可以從 "bytes" 物件讀取或填入資料而
無需額外的複製。


函式與例外
==========

此模組定義了以下例外和函式：

exception struct.error

   在各種情況下都可能觸發的例外；引數是一個描述錯誤內容的字串。

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

   回傳一個包含依照格式字串 *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)

   根據格式字串 *format* 從 *buffer* 的 *offset* 位置開始解包。即使它
   只包含一個項目，結果也都是一個元組。緩衝區從位置 *offset* 開始的位
   元組大小，必須至少達到格式所需的大小，如 "calcsize()" 所示。

struct.iter_unpack(format, buffer)

   根據格式字串 *format* 疊代地從緩衝區 *buffer* 解包。此函式回傳一個
   疊代器，它會從緩衝區讀取等大小的區塊，直到消耗完所有內容。緩衝區的
   位元組大小必須是格式所需大小的倍數，如 "calcsize()" 所示。

   每次疊代都會產生 (yield) 出一個由格式字串指定的元組。

   在 3.4 版被加入.

struct.calcsize(format)

   回傳對應於格式字串 *format* 的結構大小（因此也是 "pack(format,
   ...)" 所產生的位元組物件的大小）。


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

Format strings describe the data layout when packing and unpacking
data.  They are built up from type codes, which specify the type of
data being packed/unpacked.  In addition, special characters control
the byte order, size and alignment. Each format string consists of an
optional prefix character which describes the overall properties of
the data and one or more format characters which describe the actual
data values and padding.


位元組順序、大小和對齊
----------------------

預設情況下，C 型別以機器的原生格式和位元組順序表示，並在必要時透過跳過
填充位元組來正確對齊（根據 C 編譯器所使用的規則）。選擇此行為使得打包
結構的位元組完全對應於相對應 C 結構的記憶體配置。是否使用原生位元組順
序和填充或標準格式取決於應用程式。

或者，格式字串的第一個字元可以用來指示打包資料的位元組順序、大小和對齊
，如下表所示：

+-------------+--------------------------+------------+-------------+
| 字元        | 位元組順序               | 大小       | 對齊        |
|=============|==========================|============|=============|
| "@"         | 原生                     | 原生       | 原生        |
+-------------+--------------------------+------------+-------------+
| "="         | 原生                     | 標準       | 無          |
+-------------+--------------------------+------------+-------------+
| "<"         | 小端序                   | 標準       | 無          |
+-------------+--------------------------+------------+-------------+
| ">"         | 大端序                   | 標準       | 無          |
+-------------+--------------------------+------------+-------------+
| "!"         | 網路（= 大端序）         | 標準       | 無          |
+-------------+--------------------------+------------+-------------+

如果第一個字元不是這些字元之一，則假設為 "'@'"。

備註:

  數字 1023（十六進位為 "0x3ff"）具有以下位元組表示法：

  * 大端序（">"）為 "03 ff"

  * 小端序（"<"）為 "ff 03"

  Python 範例：

  >>> import struct
  >>> struct.pack('>h', 1023)
  b'\x03\xff'
  >>> struct.pack('<h', 1023)
  b'\xff\x03'

原生位元組順序是大端序或小端序，會取決於主機系統。例如，Intel x86、
AMD64 (x86-64)和 Apple M1 是小端序；IBM z 和許多舊架構是大端序。可使用
"sys.byteorder" 來檢查你系統的位元組順序。

原生大小和對齊是使用 C 編譯器的 "sizeof" 運算式來決定的。這總是與原生
位元組順序結合使用。

Standard size depends only on the type code;  see the table in the
Type Codes section.

請注意 "'@'" 和 "'='" 之間的差異：兩者都使用原生位元組順序，但後者的大
小和對齊是標準化的。

"'!'" 形式表示網路位元組順序，根據 IETF RFC 1700 的定義，它總是大端序
。

沒有方法來指示非原生位元組順序（強制位元組交換）；請使用適當的 "'<'"
或 "'>'" 選擇。

註解：

1. 填充只會在連續的結構成員之間自動加入。編碼結構的開頭或結尾不會加入
   填充。

2. 使用非原生大小和對齊時，例如使用 '<'、'>'、'=' 和 '!' 時，不會加入
   填充。

3. 要將結構的結尾對齊到特定型別的對齊需求，請以該型別的碼結束格式，重
   複次數為零。請參見範例。


Type Codes
----------

Type codes (or format codes) have the following meaning; the
conversion between C and Python values should be obvious given their
types.  The 'Standard size' column refers to the size of the packed
value in bytes when using standard size; that is, when the format
string starts with one of "'<'", "'>'", "'!'" or "'='".  When using
native size, the size of the packed value is platform-dependent.

+----------+----------------------------+----------------------+------------------+--------------+
| 格式     | C Type                     | Python 型別          | 標準大小         | 註解         |
|==========|============================|======================|==================|==============|
| "x"      | 填充位元組                 | 無值                 |                  | (7)          |
+----------+----------------------------+----------------------+------------------+--------------+
| "c"      | char                       | 長度為 1 的位元組    | 1                |              |
+----------+----------------------------+----------------------+------------------+--------------+
| "b"      | signed char                | int                  | 1                | (2)          |
+----------+----------------------------+----------------------+------------------+--------------+
| "B"      | unsigned char              | int                  | 1                | (2)          |
+----------+----------------------------+----------------------+------------------+--------------+
| "?"      | _Bool                      | bool                 | 1                | (1)          |
+----------+----------------------------+----------------------+------------------+--------------+
| "h"      | short                      | int                  | 2                | (2)          |
+----------+----------------------------+----------------------+------------------+--------------+
| "H"      | unsigned short             | int                  | 2                | (2)          |
+----------+----------------------------+----------------------+------------------+--------------+
| "i"      | int                        | int                  | 4                | (2)          |
+----------+----------------------------+----------------------+------------------+--------------+
| "I"      | unsigned int               | int                  | 4                | (2)          |
+----------+----------------------------+----------------------+------------------+--------------+
| "l"      | long                       | int                  | 4                | (2)          |
+----------+----------------------------+----------------------+------------------+--------------+
| "L"      | unsigned long              | int                  | 4                | (2)          |
+----------+----------------------------+----------------------+------------------+--------------+
| "q"      | long long                  | int                  | 8                | (2)          |
+----------+----------------------------+----------------------+------------------+--------------+
| "Q"      | unsigned long long         | int                  | 8                | (2)          |
+----------+----------------------------+----------------------+------------------+--------------+
| "n"      | "ssize_t"                  | int                  |                  | (2), (3)     |
+----------+----------------------------+----------------------+------------------+--------------+
| "N"      | "size_t"                   | int                  |                  | (2), (3)     |
+----------+----------------------------+----------------------+------------------+--------------+
| "e"      | _Float16                   | float                | 2                | (4), (6)     |
+----------+----------------------------+----------------------+------------------+--------------+
| "f"      | float                      | float                | 4                | (4)          |
+----------+----------------------------+----------------------+------------------+--------------+
| "d"      | double                     | float                | 8                | (4)          |
+----------+----------------------------+----------------------+------------------+--------------+
| "F"      | float complex              | complex              | 8                | (10)         |
+----------+----------------------------+----------------------+------------------+--------------+
| "D"      | double complex             | complex              | 16               | (10)         |
+----------+----------------------------+----------------------+------------------+--------------+
| "Zf"     | float complex              | complex              | 8                | (10)         |
+----------+----------------------------+----------------------+------------------+--------------+
| "Zd"     | double complex             | complex              | 16               | (10)         |
+----------+----------------------------+----------------------+------------------+--------------+
| "s"      | char[]                     | 位元組               |                  | (9)          |
+----------+----------------------------+----------------------+------------------+--------------+
| "p"      | char[]                     | 位元組               |                  | (8)          |
+----------+----------------------------+----------------------+------------------+--------------+
| "P"      | void*                      | int                  |                  | (2), (5)     |
+----------+----------------------------+----------------------+------------------+--------------+

在 3.3 版的變更: 新增 "'n'" 與 "'N'" 格式的支援。

在 3.6 版的變更: 新增 "'e'" 格式的支援。

在 3.14 版的變更: 新增 "'F'" 與 "'D'" 格式的支援。

在 3.15 版的變更: Added support for the "'Zf'" and "'Zd'" formats.

也參考:

  The "array" and ctypes modules, as well as third-party modules like
  numpy, use similar -- but slightly different -- type codes.

註解：

1. "'?'" 轉換碼對應於自 C99 以來 C 標準定義的 _Bool 型別。在標準模式下
   ，它由一個位元組表示。

2. 當嘗試使用任何整數轉換碼打包非整數時，如果非整數具有 "__index__()"
   方法，則會呼叫該方法在打包之前將引數轉換為整數。

   在 3.2 版的變更: 新增對非整數使用 "__index__()" 方法的支援。

3. "'n'" 和 "'N'" 轉換碼僅適用於原生大小（作為預設選擇或使用 "'@'" 位
   元組順序字元）。對於標準大小，你可以使用適合你應用程式的其他整數格
   式。

4. 對於 "'f'"、"'d'" 和 "'e'" 轉換碼，打包表示法使用 IEEE 754 binary32
   、binary64 或 binary16 格式（分別對應於 "'f'"、"'d'" 或 "'e'"），無
   論平台使用何種浮點數格式。

5. The "'P'" type code is only available for the native byte ordering
   (selected as the default or with the "'@'" byte order character).
   The byte order character "'='" chooses to use little- or big-endian
   ordering based on the host system. The struct module does not
   interpret this as native ordering, so the "'P'" format is not
   available.

6. IEEE 754 binary16「半精度 (half precision)」型別是在 2008 年的 IEEE
   754 標準修訂版中引入的。它有一個符號位元 (sign bit)、5 位元指數和
   11 位元精度（明確儲存 10 位元），可以全精度表示大約 "6.1e-05" 到
   "6.5e+04" 之間的數字。此型別未被 C 編譯器廣泛支援：若編譯器支援 C23
   標準的附錄 H，則可以作為 _Float16 型別使用。在典型機器上，unsigned
   short 可以用於儲存但不能用於數學運算。請參見 Wikipedia 上的半精度浮
   點數格式頁面以取得更多資訊。

7. 打包時，"'x'" 插入一個 NUL 位元組。

8. The "'p'" type code encodes a "Pascal string", meaning a short
   variable-length string stored in a *fixed number of bytes*, given
   by the count. The first byte stored is the length of the string, or
   255, whichever is smaller.  The bytes of the string follow.  If the
   byte string passed in to "pack()" is too long (longer than the
   count minus 1), only the leading "count-1" bytes of the string are
   stored.  If the byte string is shorter than "count-1", it is padded
   with null bytes so that exactly count bytes in all are used.  Note
   that for "unpack()", the "'p'" type code consumes "count" bytes,
   but that the "bytes" object returned can never contain more than
   255 bytes. When packing, arguments of types "bytes" and "bytearray"
   are accepted.

9. For the "'s'" type code, the count is interpreted as the length of
   the byte string, not a repeat count like for the other type codes;
   for example, "'10s'" means a single 10-byte string mapping to or
   from a single Python byte string, while "'10c'" means 10 separate
   one byte character elements (e.g., "cccccccccc") mapping to or from
   ten different Python byte objects. (See 範例 for a concrete
   demonstration of the difference.) If a count is not given, it
   defaults to 1.  For packing, the byte 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 byte string
   (while "'0c'" means 0 characters). When packing, arguments of types
   "bytes" and "bytearray" are accepted.

10. For the "'F'" and "'D'" type codes, the packed representation uses
    the IEEE 754 binary32 and binary64 format for components of the
    complex number, regardless of the floating-point format used by
    the platform. Note that complex types ("F"/"Zf" and "D"/"Zd") are
    available unconditionally, despite complex types being an optional
    feature in C. As specified in the C11 standard, each complex type
    is represented by a two-element C array containing, respectively,
    the real and imaginary parts.

A type code may be preceded by an integral repeat count.  For example,
the format string "'4h'" means exactly the same as "'hhhh'".

格式之間的空白字元會被忽略；但是計數和其格式不能包含空白字元。

當使用整數格式之一（"'b'"、"'B'"、"'h'"、"'H'"、"'i'"、"'I'"、"'l'"、
"'L'"、"'q'"、"'Q'"）打包數值 "x" 時，如果 "x" 超出該格式的有效範圍，
則會觸發 "struct.error"。

在 3.1 版的變更: 以前一些整數格式會環繞超出範圍的數值並引發
"DeprecationWarning" 而不是 "struct.error"。

For the "'?'" type code, the return value is either "True" or "False".
When packing, the truth value of the argument object is used. Either 0
or 1 in the native or standard bool representation will be packed, and
any non-zero value will be "True" when unpacking.


範例
----

備註:

  原生位元組順序範例（由 "'@'" 格式前綴或缺少任何前綴字元指定）可能與
  讀者機器產生的結果不符，因為這取決於平台和編譯器。

使用大端序打包和解包三種不同大小的整數：

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

嘗試打包對於定義欄位來說太大的整數：

   >>> pack(">h", 99999)
   Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
   struct.error: 'h' format requires -32768 <= number <= 32767

示範 "'s'" 和 "'c'" 格式字元之間的差異：

   >>> pack("@ccc", b'1', b'2', b'3')
   b'123'
   >>> pack("@3s", b'123')
   b'123'

解包的欄位可以透過將其指派給變數或將結果包裝在具名元組中來命名：

   >>> 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 type codes may have an impact on size in native mode
since padding is implicit. In standard mode, the user is responsible
for inserting any desired padding. Note in the first "pack" call below
that three NUL bytes were added after the packed "'#'" to align the
following integer on a four-byte boundary. In this example, the output
was produced on a little endian machine:

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

假設平台的 long 對齊到 4 位元組邊界，以下格式 "'llh0l'" 會在結尾加入兩
個填充位元組：

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

也參考:

  "array" 模組
     同質資料的打包二進位儲存。

  "json" 模組
     JSON 編碼器和解碼器。

  "pickle" 模組
     Python 物件序列化。


應用
====

"struct" 模組有兩種主要應用程式：在應用程式內或使用相同編譯器編譯的另
一個應用程式之間進行 Python 和 C 程式碼的資料交換（原生格式），以及使
用約定資料配置的應用程式之間的資料交換（標準格式）。一般來說，為這兩個
領域建構的格式字串是不同的。


原生格式
--------

When constructing format strings which mimic native layouts, the
compiler and machine architecture determine byte ordering and padding.
In such cases, the "@" format character should be used to specify
native byte ordering and data sizes.  Internal pad bytes are normally
inserted automatically.  It is possible that a zero-repeat type code
will be needed at the end of a format string to round up to the
correct byte boundary for proper alignment of consecutive chunks of
data.

考慮這兩個簡單範例（在 64 位元小端序機器上）：

   >>> calcsize('@lhl')
   24
   >>> calcsize('@llh')
   18

在第二個格式字串的結尾，如果不使用額外填充，資料不會填充到 8 位元組邊
界。零重複格式碼解決了這個問題：

   >>> calcsize('@llh0l')
   24

The "'x'" type code can be used to specify the repeat, but for native
formats it is better to use a zero-repeat format like "'0l'".

預設使用原生位元組順序和對齊，但最好明確使用 "'@'" 前綴字元。


標準格式
--------

當與你的行程之外的網路或儲存區等交換資料時，要夠精確。指定確切的位元組
順序、大小和對齊。不要假設它們與特定機器的原生順序匹配。例如，網路位元
組順序是大端序，而許多流行的 CPU 是小端序。透過明確定義這一點，使用者
無需關心其程式碼運行的平台細節。第一個字元通常應該是 "<" 或 ">"（或
"!"）。填充是程式設計師的責任。零重複格式字元不會起作用。取而代之的是
使用者必須在需要的地方明確加入 "'x'" 填充位元組。重新檢視上一節的範例
，我們有：

   >>> calcsize('<qh6xq')
   24
   >>> pack('<qh6xq', 1, 2, 3) == pack('@lhl', 1, 2, 3)
   True
   >>> calcsize('@llh')
   18
   >>> pack('@llh', 1, 2, 3) == pack('<qqh', 1, 2, 3)
   True
   >>> calcsize('<qqh6x')
   24
   >>> calcsize('@llh0l')
   24
   >>> pack('@llh0l', 1, 2, 3) == pack('<qqh6x', 1, 2, 3)
   True

上述結果（在 64 位元機器上執行）和在不同機器上執行時不保證會匹配。例如
，下面的範例是在 32 位元機器上執行的：

   >>> calcsize('<qqh6x')
   24
   >>> calcsize('@llh0l')
   12
   >>> pack('@llh0l', 1, 2, 3) == pack('<qqh6x', 1, 2, 3)
   False


類別
====

"struct" 模組也定義了以下型別：

class struct.Struct(format)

   回傳一個新的 Struct 物件，它會根據格式字串 *format* 寫入和讀取二進
   位資料。建立一次 "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()" 方法所產
      生的位元組物件的大小）。

   在 3.13 版的變更: 結構的 *repr()* 已經改變。現在是：

   >>> Struct('i')
   Struct('i')
