Extending Python with C or C++中介紹了Python的C extension的寫法,它給出的範例前兩行如下:
#define PY_SSIZE_T_CLEAN
#include
其中#define PY_SSIZE_T_CLEAN
的作用為何?簡單來說是讓用於解析extensions functions/methods參數的PyArg_ParseTuple
函數把s#
的長度參數當成Py_ssize_t
而非int
型別。
參考Parsing arguments and building values - Strings and buffers,PyArg_ParseTuple
的s#
有兩個參數:
s# (str, read-only bytes-like object) [const char *, Py_ssize_t]
分別代表字串本身及其長度,其中長度的型別必須是Py_ssize_t
。
根據以下說明:
Note For all # variants of formats (s#, y#, etc.), the macro PY_SSIZE_T_CLEAN must be defined before including Python.h. On Python 3.9 and older, the type of the length argument is Py_ssize_t if the PY_SSIZE_T_CLEAN macro is defined, or int otherwise.
可以知道s#
長度參數的型別預設是int
,如果定義了PY_SSIZE_T_CLEAN
,才會是Py_ssize_t
型別。因此必須定義PY_SSIZE_T_CLEAN
,否則會出現如SystemError: PY_SSIZE_T_CLEAN macro must be defined for ‘#’ formats的錯誤。
至於Py_ssize_t
是什麼呢?參考Py_ssize_t:
type Py_ssize_t
Part of the Stable ABI.
A signed integral type such that sizeof(Py_ssize_t) == sizeof(size_t). C99 doesn’t define such a thing directly (size_t is an unsigned integral type). See PEP 353 for details. PY_SSIZE_T_MAX is the largest positive value of type Py_ssize_t.
可知Py_ssize_t
是一有號整數的型別,其長度等於size_t
。而根據C size_t,size_t
的大小不一定等於int
,所以Python中才會有必須定義PY_SSIZE_T_CLEAN
的規定。