解析引數和構建值¶
這些函式在建立您自己的擴充套件函式和方法時非常有用。更多資訊和示例可以在擴充套件和嵌入 Python 直譯器中找到。
前三個描述的函式,PyArg_ParseTuple()
、PyArg_ParseTupleAndKeywords()
和PyArg_Parse()
,都使用格式字串來告知函式有關預期引數的資訊。這些函式的格式字串使用相同的語法。
解析引數¶
格式字串由零個或多個“格式單元”組成。格式單元描述一個 Python 物件;它通常是一個字元或一個帶括號的格式單元序列。除少數例外,非帶括號序列的格式單元通常對應於這些函式的單個地址引數。在以下描述中,帶引號的形式是格式單元;(圓)括號中的條目是與格式單元匹配的 Python 物件型別;[方]括號中的條目是應傳遞其地址的 C 變數的型別。
字串和緩衝區¶
注意
在 Python 3.12 及更早版本中,必須在包含 Python.h
之前定義宏 PY_SSIZE_T_CLEAN
,才能使用下面解釋的所有格式的 #
變體(s#
、y#
等)。這在 Python 3.13 及更高版本中不是必需的。
這些格式允許將物件作為連續的記憶體塊訪問。您無需為返回的 Unicode 或位元組區域提供原始儲存。
除非另有說明,否則緩衝區不是以 NUL 結尾的。
有三種方法可以將字串和緩衝區轉換為 C
諸如
y*
和s*
之類的格式會填充Py_buffer
結構。 這會鎖定底層緩衝區,以便呼叫者隨後可以使用該緩衝區,即使在Py_BEGIN_ALLOW_THREADS
塊內,也不會有可變資料被調整大小或銷燬的風險。 因此,**您必須呼叫**PyBuffer_Release()
,在您完成處理資料之後(或在任何提前中止的情況下)。es
、es#
、et
和et#
格式分配結果緩衝區。 **您必須呼叫**PyMem_Free()
,在您完成處理資料之後(或在任何提前中止的情況下)。其他格式接受
str
或只讀的 類位元組物件,例如bytes
,併為其緩衝區提供一個const char *
指標。在這種情況下,緩衝區是“借用”的:它由相應的 Python 物件管理,並共享此物件的生命週期。您無需自己釋放任何記憶體。為確保可以安全地借用底層緩衝區,物件的
PyBufferProcs.bf_releasebuffer
欄位必須為NULL
。 這不允許使用常見的可變物件,例如bytearray
,但也禁止使用某些只讀物件,例如bytes
的memoryview
。除了此
bf_releasebuffer
要求之外,沒有檢查來驗證輸入物件是否是不可變的(例如,它是否會響應可寫緩衝區的請求,或者另一個執行緒是否可以更改資料)。
s
(str
) [const char *]將 Unicode 物件轉換為指向字元字串的 C 指標。指向現有字串的指標儲存在您傳遞其地址的字元指標變數中。 C 字串以 NUL 結尾。Python 字串不得包含嵌入的空程式碼點;如果包含,則會引發
ValueError
異常。Unicode 物件使用'utf-8'
編碼轉換為 C 字串。如果此轉換失敗,則會引發UnicodeError
。注意
此格式不接受 類位元組物件。如果您想接受檔案系統路徑並將它們轉換為 C 字元字串,則最好使用帶有
PyUnicode_FSConverter()
作為*轉換器*的O&
格式。在 3.5 版本中更改:之前,當在 Python 字串中遇到嵌入的空程式碼點時,會引發
TypeError
。s*
(str
或 類位元組物件) [Py_buffer]此格式接受 Unicode 物件以及類位元組物件。 它會填充呼叫者提供的
Py_buffer
結構。 在這種情況下,生成的 C 字串可能包含嵌入的 NUL 位元組。 Unicode 物件使用'utf-8'
編碼轉換為 C 字串。s#
(str
, 只讀的 類位元組物件) [const char *,Py_ssize_t
]類似於
s*
,但它提供一個借用的緩衝區。結果儲存到兩個 C 變數中,第一個是指向 C 字串的指標,第二個是其長度。該字串可能包含嵌入的空位元組。Unicode 物件使用'utf-8'
編碼轉換為 C 字串。z
(str
或None
) [const char *]類似於
s
,但 Python 物件也可能是None
,在這種情況下,C 指標設定為NULL
。z*
(str
、類位元組物件 或None
) [Py_buffer]類似於
s*
,但 Python 物件也可能是None
,在這種情況下,Py_buffer
結構的buf
成員設定為NULL
。z#
(str
、只讀的 類位元組物件 或None
) [const char *,Py_ssize_t
]類似於
s#
,但 Python 物件也可以是None
,在這種情況下,C 指標會被設定為NULL
。y
(只讀的類位元組物件) [const char *]此格式將類位元組物件轉換為 C 指標,指向一個借用的字串;它不接受 Unicode 物件。位元組緩衝區不能包含嵌入的空位元組;如果包含,則會引發
ValueError
異常。在 3.5 版本中更改: 之前,如果在位元組緩衝區中遇到嵌入的空位元組,會引發
TypeError
。y*
(類位元組物件) [Py_buffer]此
s*
的變體不接受 Unicode 物件,只接受類位元組物件。這是接受二進位制資料的推薦方式。y#
(只讀的類位元組物件) [const char *,Py_ssize_t
]此
s#
的變體不接受 Unicode 物件,只接受類位元組物件。S
(bytes
) [PyBytesObject *]要求 Python 物件是
bytes
物件,不嘗試任何轉換。如果物件不是 bytes 物件,則會引發TypeError
。C 變數也可以宣告為 PyObject*。Y
(bytearray
) [PyByteArrayObject *]要求 Python 物件是
bytearray
物件,不嘗試任何轉換。如果物件不是bytearray
物件,則會引發TypeError
。C 變數也可以宣告為 PyObject*。U
(str
) [PyObject *]要求 Python 物件是 Unicode 物件,不嘗試任何轉換。如果物件不是 Unicode 物件,則會引發
TypeError
。C 變數也可以宣告為 PyObject*。w*
(可讀寫的類位元組物件) [Py_buffer]此格式接受任何實現可讀寫緩衝區介面的物件。它會填充呼叫者提供的
Py_buffer
結構。緩衝區可能包含嵌入的空位元組。呼叫者在完成緩衝區操作後必須呼叫PyBuffer_Release()
。es
(str
) [const char *encoding, char **buffer]此
s
的變體用於將 Unicode 編碼為字元緩衝區。它只適用於不包含嵌入 NUL 位元組的編碼資料。此格式需要兩個引數。第一個引數僅用作輸入,必須是一個指向以 NUL 結尾的編碼名稱字串的 const char*,或者為
NULL
,在這種情況下會使用'utf-8'
編碼。如果 Python 不知道指定的編碼,則會引發異常。第二個引數必須是 char**;它引用的指標的值將被設定為包含引數文字內容的緩衝區。文字將使用第一個引數指定的編碼進行編碼。PyArg_ParseTuple()
將分配所需大小的緩衝區,將編碼資料複製到此緩衝區,並調整 *buffer 以引用新分配的儲存空間。呼叫者有責任在使用後呼叫PyMem_Free()
來釋放已分配的緩衝區。et
(str
,bytes
或bytearray
) [const char *encoding, char **buffer]與
es
相同,不同之處在於位元組字串物件會直接傳遞,不進行重新編碼。相反,實現會假定位元組字串物件使用作為引數傳入的編碼。es#
(str
) [const char *encoding, char **buffer,Py_ssize_t
*buffer_length]此
s#
的變體用於將 Unicode 編碼為字元緩衝區。與es
格式不同,此變體允許輸入包含 NUL 字元的資料。它需要三個引數。第一個引數僅用作輸入,必須是一個指向以 NUL 結尾的編碼名稱字串的 const char*,或者為
NULL
,在這種情況下會使用'utf-8'
編碼。如果 Python 不知道指定的編碼,則會引發異常。第二個引數必須是 char**;它引用的指標的值將被設定為包含引數文字內容的緩衝區。文字將使用第一個引數指定的編碼進行編碼。第三個引數必須是指向整數的指標;引用的整數將被設定為輸出緩衝區中的位元組數。有兩種操作模式
如果 *buffer 指向一個
NULL
指標,函式將分配所需大小的緩衝區,將編碼資料複製到此緩衝區,並將 *buffer 設定為引用新分配的儲存空間。呼叫者有責任在使用後呼叫PyMem_Free()
來釋放已分配的緩衝區。如果 *buffer 指向一個非
NULL
指標(已分配的緩衝區),PyArg_ParseTuple()
將使用此位置作為緩衝區,並將 *buffer_length 的初始值解釋為緩衝區大小。然後,它會將編碼資料複製到緩衝區並以 NUL 結尾。如果緩衝區不夠大,則會設定ValueError
。在這兩種情況下,*buffer_length 都會被設定為編碼資料的長度,不包括結尾的 NUL 位元組。
et#
(str
,bytes
或bytearray
) [const char *encoding, char **buffer,Py_ssize_t
*buffer_length]與
es#
相同,不同之處在於位元組字串物件會直接傳遞,不進行重新編碼。相反,實現會假定位元組字串物件使用作為引數傳入的編碼。
在 3.12 版本中更改: 刪除了 u
、 u#
、 Z
和 Z#
,因為它們使用了舊式的 Py_UNICODE*
表示形式。
數字¶
b
(int
) [unsigned char]將一個非負 Python 整數轉換為一個無符號的小整數,儲存在 C unsigned char 中。
B
(int
) [unsigned char]將一個 Python 整數轉換為一個小整數,不進行溢位檢查,儲存在 C unsigned char 中。
h
(int
) [short int]將 Python 整數轉換為 C short int。
H
(int
) [unsigned short int]將 Python 整數轉換為 C unsigned short int,不進行溢位檢查。
i
(int
) [int]將 Python 整數轉換為普通的 C int。
I
(int
) [unsigned int]將 Python 整數轉換為 C unsigned int,不進行溢位檢查。
l
(int
) [long int]將 Python 整數轉換為 C long int。
k
(int
) [unsigned long]將 Python 整數轉換為 C unsigned long,不進行溢位檢查。
L
(int
) [long long]將 Python 整數轉換為 C long long。
K
(int
) [unsigned long long]將 Python 整數轉換為 C unsigned long long,不進行溢位檢查。
n
(int
) [Py_ssize_t
]將 Python 整數轉換為 C
Py_ssize_t
。c
(bytes
或bytearray
,長度為 1) [char]將一個 Python 位元組(表示為長度為 1 的
bytes
或bytearray
物件)轉換為 C char。3.3 版本更改: 允許使用
bytearray
物件。C
(str
,長度為 1) [int]將一個 Python 字元(表示為長度為 1 的
str
物件)轉換為 C int。f
(float
) [float]將 Python 浮點數轉換為 C float。
d
(float
) [double]將 Python 浮點數轉換為 C double。
D
(complex
) [Py_complex]將 Python 複數轉換為 C
Py_complex
結構體。
其他物件¶
O
(物件) [PyObject *]將 Python 物件(不進行任何轉換)儲存在 C 物件指標中。因此,C 程式接收到傳遞的實際物件。不會建立對該物件新的強引用(即其引用計數不會增加)。儲存的指標不為
NULL
。O!
(物件) [typeobject, PyObject *]將 Python 物件儲存在 C 物件指標中。這與
O
類似,但需要兩個 C 引數:第一個是 Python 型別物件的地址,第二個是儲存物件指標的 C 變數(型別為 PyObject*)的地址。如果 Python 物件不具有所需的型別,則會引發TypeError
。
O&
(物件) [converter, anything]透過 converter 函式將 Python 物件轉換為 C 變數。這需要兩個引數:第一個是函式,第二個是 C 變數(任意型別)的地址,轉換為 void*。converter 函式依次呼叫如下
status = converter(object, address);
其中 object 是要轉換的 Python 物件,address 是傳遞給
PyArg_Parse*
函式的 void* 引數。返回的 status 對於成功轉換應為1
,如果轉換失敗則為0
。當轉換失敗時,converter 函式應引發異常,並保持 address 的內容不變。如果 converter 返回
Py_CLEANUP_SUPPORTED
,則如果引數解析最終失敗,它可能會被第二次呼叫,從而使轉換器有機會釋放它已經分配的任何記憶體。在第二次呼叫中,object 引數將為NULL
;address 將具有與原始呼叫相同的值。3.1 版本更改: 添加了
Py_CLEANUP_SUPPORTED
。p
(bool
) [int]測試傳入值的真值(布林 **p**redicate),並將結果轉換為等效的 C 真/假整數值。如果表示式為真,則將 int 設定為
1
,如果為假,則設定為0
。 這接受任何有效的 Python 值。有關 Python 如何測試值的真值,請參閱 真值測試。3.3 版本新增。
(items)
(tuple
) [matching-items]該物件必須是 Python 序列,其長度是 items 中格式單元的數量。C 引數必須與 items 中的各個格式單元相對應。序列的格式單元可以是巢狀的。
可以傳遞 “long” 整數(其值超過平臺 LONG_MAX
的整數),但是不進行適當的範圍檢查——當接收欄位太小而無法接收該值時,最高有效位會被靜默截斷(實際上,語義是從 C 中的向下轉換繼承的——你的結果可能會有所不同)。
在格式字串中,其他幾個字元具有含義。這些字元可能不會出現在巢狀的括號內。它們是:
|
指示 Python 引數列表中剩餘的引數是可選的。與可選引數對應的 C 變數應初始化為它們的預設值——當未指定可選引數時,
PyArg_ParseTuple()
不會觸及相應的 C 變數的內容。$
PyArg_ParseTupleAndKeywords()
專用:指示 Python 引數列表中剩餘的引數是僅關鍵字的。目前,所有僅關鍵字的引數也必須是可選引數,因此在格式字串中,$
之前必須始終指定|
。3.3 版本新增。
:
格式單元列表在此處結束;冒號後的字串用作錯誤訊息中的函式名稱(
PyArg_ParseTuple()
引發的異常的 “關聯值”)。;
格式單元列表在此處結束;分號後的字串用作錯誤訊息,*代替*預設錯誤訊息。
:
和;
相互排斥。
請注意,提供給呼叫者的任何 Python 物件引用都是*借用*的引用;請不要釋放它們(即,不要減少它們的引用計數)!
傳遞給這些函式的附加引數必須是變數的地址,這些變數的型別由格式字串確定;它們用於儲存來自輸入元組的值。在上面格式單元列表中描述的少數情況下,這些引數用作輸入值;在這種情況下,它們應與相應格式單元指定的內容匹配。
為了成功轉換,arg 物件必須與格式匹配,並且格式必須耗盡。成功時,PyArg_Parse*
函式返回 true,否則返回 false 並引發適當的異常。當 PyArg_Parse*
函式由於某個格式單元的轉換失敗而失敗時,與該格式單元及其後續格式單元對應的地址處的變數將保持不變。
API 函式¶
-
int PyArg_ParseTuple(PyObject *args, const char *format, ...)¶
- 屬於 穩定 ABI 的一部分。
將僅接受位置引數的函式的引數解析為區域性變數。成功時返回 true;失敗時,返回 false 並引發適當的異常。
-
int PyArg_VaParse(PyObject *args, const char *format, va_list vargs)¶
- 屬於 穩定 ABI 的一部分。
與
PyArg_ParseTuple()
相同,但它接受 va_list 而不是可變數量的引數。
-
int PyArg_ParseTupleAndKeywords(PyObject *args, PyObject *kw, const char *format, char *const *keywords, ...)¶
- 屬於 穩定 ABI 的一部分。
將接受位置引數和關鍵字引數的函式的引數解析為區域性變數。keywords 引數是一個以
NULL
結尾的關鍵字引數名稱陣列,指定為以 null 結尾的 ASCII 或 UTF-8 編碼的 C 字串。空名稱表示僅限位置引數。成功時返回 true;失敗時,返回 false 並引發適當的異常。注意
keywords 引數宣告在 C 中為 char *const*,在 C++ 中為 const char *const*。這可以使用
PY_CXX_CONST
宏覆蓋。在 3.6 版本中更改: 添加了對僅限位置引數的支援。
在 3.13 版本中更改: keywords 引數現在在 C 中的型別為 char *const*,在 C++ 中的型別為 const char *const*,而不是 char**。添加了對非 ASCII 關鍵字引數名稱的支援。
-
int PyArg_VaParseTupleAndKeywords(PyObject *args, PyObject *kw, const char *format, char *const *keywords, va_list vargs)¶
- 屬於 穩定 ABI 的一部分。
與
PyArg_ParseTupleAndKeywords()
相同,但它接受 va_list 而不是可變數量的引數。
-
int PyArg_ValidateKeywordArguments(PyObject*)¶
- 屬於 穩定 ABI 的一部分。
確保關鍵字引數字典中的鍵是字串。只有在不使用
PyArg_ParseTupleAndKeywords()
時才需要這樣做,因為後者已經執行此檢查。在 3.2 版本中新增。
-
int PyArg_Parse(PyObject *args, const char *format, ...)¶
- 屬於 穩定 ABI 的一部分。
將接受單個位置引數的函式的引數解析為區域性變數。成功時返回 true;失敗時,返回 false 並引發適當的異常。
示例
// Function using METH_O calling convention static PyObject* my_function(PyObject *module, PyObject *arg) { int value; if (!PyArg_Parse(arg, "i:my_function", &value)) { return NULL; } // ... use value ... }
-
int PyArg_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t max, ...)¶
- 屬於 穩定 ABI 的一部分。
一種更簡單的引數檢索形式,它不使用格式字串來指定引數的型別。使用此方法檢索其引數的函式應在函式或方法表中宣告為
METH_VARARGS
。包含實際引數的元組應作為 args 傳遞;它實際上必須是一個元組。元組的長度必須至少為 min,且不超過 max;min 和 max 可以相等。必須將附加引數傳遞給函式,其中每個引數都應是指向 PyObject* 變數的指標;這些變數將用來自 args 的值填充;它們將包含借用引用。與 args 未給出的可選引數對應的變數將不會被填充;這些變數應由呼叫者初始化。此函式在成功時返回 true,如果 args 不是元組或包含錯誤數量的元素,則返回 false;如果出現故障,則會設定異常。這是使用此函式的示例,取自弱引用的
_weakref
幫助模組的原始碼static PyObject * weakref_ref(PyObject *self, PyObject *args) { PyObject *object; PyObject *callback = NULL; PyObject *result = NULL; if (PyArg_UnpackTuple(args, "ref", 1, 2, &object, &callback)) { result = PyWeakref_NewRef(object, callback); } return result; }
在此示例中呼叫
PyArg_UnpackTuple()
完全等效於此呼叫PyArg_ParseTuple()
PyArg_ParseTuple(args, "O|O:ref", &object, &callback)
-
PY_CXX_CONST¶
在
PyArg_ParseTupleAndKeywords()
和PyArg_VaParseTupleAndKeywords()
的 keywords 引數宣告中,在 char *const* 前要插入的值(如果有)。C 語言預設為空,C++ 語言預設為const
(const char *const*)。要覆蓋此預設值,請在包含Python.h
之前將其定義為所需的值。3.13 版本中新增。
構建值¶
-
PyObject *Py_BuildValue(const char *format, ...)¶
- 返回值:新引用。屬於穩定 ABI 的一部分。
基於類似於
PyArg_Parse*
系列函式所接受的格式字串和一系列值建立一個新值。如果發生錯誤,則返回該值或NULL
;如果返回NULL
,則會引發異常。Py_BuildValue()
並非總是構建一個元組。僅當其格式字串包含兩個或更多格式單元時,它才會構建一個元組。如果格式字串為空,則返回None
;如果它恰好包含一個格式單元,則返回該格式單元所描述的任何物件。要強制它返回大小為 0 或 1 的元組,請將格式字串用括號括起來。當記憶體緩衝區作為引數傳遞以提供構建物件的資料時(例如對於
s
和s#
格式),會複製所需的資料。呼叫者提供的緩衝區永遠不會被Py_BuildValue()
建立的物件引用。換句話說,如果您的程式碼呼叫malloc()
並將分配的記憶體傳遞給Py_BuildValue()
,則您的程式碼負責在Py_BuildValue()
返回後為該記憶體呼叫free()
。在以下描述中,帶引號的形式是格式單元;圓括號中的條目是格式單元將返回的 Python 物件型別;方括號中的條目是要傳遞的 C 值型別。
空格、製表符、冒號和逗號在格式字串中會被忽略(但在
s#
等格式單元內則不會)。這可以用來使長格式字串更具可讀性。s
(str
或None
) [const char *]使用
'utf-8'
編碼將以 null 結尾的 C 字串轉換為 Pythonstr
物件。如果 C 字串指標為NULL
,則使用None
。s#
(str
或None
) [const char *,Py_ssize_t
]使用
'utf-8'
編碼將 C 字串及其長度轉換為 Pythonstr
物件。如果 C 字串指標為NULL
,則忽略長度並返回None
。y
(bytes
) [const char *]這將 C 字串轉換為 Python
bytes
物件。如果 C 字串指標為NULL
,則返回None
。y#
(bytes
) [const char *,Py_ssize_t
]這將 C 字串及其長度轉換為 Python 物件。如果 C 字串指標為
NULL
,則返回None
。z
(str
或None
) [const char *]與
s
相同。z#
(str
或None
) [const char *,Py_ssize_t
]與
s#
相同。u
(str
) [const wchar_t *]將以 null 結尾的 Unicode(UTF-16 或 UCS-4)資料的
wchar_t
緩衝區轉換為 Python Unicode 物件。如果 Unicode 緩衝區指標為NULL
,則返回None
。u#
(str
) [const wchar_t *,Py_ssize_t
]將 Unicode(UTF-16 或 UCS-4)資料緩衝區及其長度轉換為 Python Unicode 物件。如果 Unicode 緩衝區指標為
NULL
,則忽略長度並返回None
。U
(str
或None
) [const char *]與
s
相同。U#
(str
或None
) [const char *,Py_ssize_t
]與
s#
相同。i
(int
) [int]將普通 C int 轉換為 Python 整數物件。
b
(int
) [char]將普通 C char 轉換為 Python 整數物件。
h
(int
) [short int]將普通 C short int 轉換為 Python 整數物件。
l
(int
) [long int]將 C long int 轉換為 Python 整數物件。
B
(int
) [unsigned char]將 C unsigned char 轉換為 Python 整數物件。
H
(int
) [unsigned short int]將 C unsigned short int 轉換為 Python 整數物件。
I
(int
) [unsigned int]將 C unsigned int 轉換為 Python 整數物件。
k
(int
) [unsigned long]將 C unsigned long 轉換為 Python 整數物件。
L
(int
) [long long]將 C long long 轉換為 Python 整數物件。
K
(int
) [unsigned long long]將 C unsigned long long 轉換為 Python 整數物件。
n
(int
) [Py_ssize_t
]將 C
Py_ssize_t
轉換為 Python 整數。c
(長度為 1 的bytes
) [char]將表示位元組的 C int 轉換為長度為 1 的 Python
bytes
物件。C
(str
,長度為 1) [int]將表示字元的 C int 轉換為長度為 1 的 Python
str
物件。d
(float
) [double]將 C double 轉換為 Python 浮點數。
f
(float
) [float]將 C float 轉換為 Python 浮點數。
D
(complex
) [Py_complex *]將 C
Py_complex
結構體轉換為 Python 複數。O
(物件) [PyObject *]傳遞一個 Python 物件,不做任何修改,但建立一個新的強引用(即其引用計數加一)。如果傳入的物件是
NULL
指標,則假定這是因為產生該引數的呼叫發現了一個錯誤並設定了異常。因此,Py_BuildValue()
將返回NULL
但不會引發異常。如果尚未引發任何異常,則會設定SystemError
。S
(物件) [PyObject *]與
O
相同。N
(物件) [PyObject *]與
O
相同,但它不建立新的強引用。當物件是由引數列表中的物件建構函式的呼叫建立時,此項很有用。O&
(物件) [converter, anything]透過 *轉換器* 函式將 *任何內容* 轉換為 Python 物件。該函式使用 *任何內容*(應與 void* 相容)作為其引數進行呼叫,並應返回一個“新”Python 物件,如果發生錯誤,則返回
NULL
。(items)
(tuple
) [matching-items]將一系列 C 值轉換為具有相同數量項的 Python 元組。
[items]
(list
) [匹配項]將一系列 C 值轉換為具有相同數量項的 Python 列表。
{items}
(dict
) [匹配項]將一系列 C 值轉換為 Python 字典。每對連續的 C 值都會向字典新增一項,分別作為鍵和值。
如果格式字串中存在錯誤,則會設定
SystemError
異常並返回NULL
。
-
PyObject *Py_VaBuildValue(const char *format, va_list vargs)¶
- 返回值:新引用。屬於穩定 ABI 的一部分。
與
Py_BuildValue()
相同,只不過它接受 va_list 而不是可變數量的引數。