`PyTuple_Pack` 段错误
`PyTuple_Pack` segfault
我在 Python 扩展模块中有一个函数 foo
,它应该 return 一个整数元组到 Python。这可以使用 Py_BuildValue
:
轻松完成
static PyObject*
foo(PyObject* self, PyObject* args)
{
int a = 0;
int b = 0;
/* calculations and stuff */
PyObject* out = Py_BuildValue("(iii)", a, b, a+b);
Py_INCREF(out);
return out;
}
我想使用 PyTuple_Pack
而不是 Py_BuildValue
,它确保 return 值确实是一个元组。
Python C API documentation 表示 PyTuple_Pack(3, a, b, a+b)
等同于 Py_BuildValue("(iii)", a, b, a+b)
。两个函数 return 类型 PyPbject*
的新引用。
因此,根据上面的代码,
static PyObject*
foo(PyObject* self, PyObject* args)
{
/* ... */
PyObject* out = PyTuple_Pack(3, a, b, a+b);
Py_INCREF(out);
return out;
}
应该可以解决问题,但事实并非如此。相反,我得到了一个段错误。
我在这里错过了什么?
区别是:
Py_BuildValue("(ii)", a, b)
期望 a
和 b
是简单的 C-int 值。
PyTuple_Pack(2, a, b)
期望 a
和 b
已经是 PyObject
(而不是 C-int)。
The tuple values are initialized to the subsequent n C arguments pointing to Python objects. PyTuple_Pack(2, a, b)
is equivalent to Py_BuildValue("(OO)", a, b)
.
为了使用 PyTuple_Pack
,您需要先将整数值转换为 Python-整数。
使用起来更简单Py_BuildValue()
。如果在 Py_BuildValue
中用括号括起格式字符串,结果将是一个元组:
Py_BuildValue()
does not always build a tuple. It builds a tuple only if its format string contains two or more format units. If the format string is empty, it returns None; if it contains exactly one format unit, it returns whatever object is described by that format unit. To force it to return a tuple of size 0 or one, parenthesize the format string.
这意味着:如果您从至少两个元素构造一个元组,则无需担心:
Py_BuildValue("ii", a, b) # returns a tuple
Py_BuildValue("(ii)", a, b) # returns a tuple
如果只有一个元素就不一样了:
Py_BuildValue("i", a) # returns an integer
# parenthesized:
Py_BuildValue("(i)", a) # returns a tuple with an integer
或根本没有元素:
Py_BuildValue("") # returns None
# parenthesized:
Py_BuildValue("()") # returns an empty tuple.
所以只要确保格式字符串中有括号,返回值将是一个元组。
我在 Python 扩展模块中有一个函数 foo
,它应该 return 一个整数元组到 Python。这可以使用 Py_BuildValue
:
static PyObject*
foo(PyObject* self, PyObject* args)
{
int a = 0;
int b = 0;
/* calculations and stuff */
PyObject* out = Py_BuildValue("(iii)", a, b, a+b);
Py_INCREF(out);
return out;
}
我想使用 PyTuple_Pack
而不是 Py_BuildValue
,它确保 return 值确实是一个元组。
Python C API documentation 表示 PyTuple_Pack(3, a, b, a+b)
等同于 Py_BuildValue("(iii)", a, b, a+b)
。两个函数 return 类型 PyPbject*
的新引用。
因此,根据上面的代码,
static PyObject*
foo(PyObject* self, PyObject* args)
{
/* ... */
PyObject* out = PyTuple_Pack(3, a, b, a+b);
Py_INCREF(out);
return out;
}
应该可以解决问题,但事实并非如此。相反,我得到了一个段错误。 我在这里错过了什么?
区别是:
Py_BuildValue("(ii)", a, b)
期望a
和b
是简单的 C-int 值。PyTuple_Pack(2, a, b)
期望a
和b
已经是PyObject
(而不是 C-int)。
The tuple values are initialized to the subsequent n C arguments pointing to Python objects.
PyTuple_Pack(2, a, b)
is equivalent toPy_BuildValue("(OO)", a, b)
.
为了使用 PyTuple_Pack
,您需要先将整数值转换为 Python-整数。
使用起来更简单Py_BuildValue()
。如果在 Py_BuildValue
中用括号括起格式字符串,结果将是一个元组:
Py_BuildValue()
does not always build a tuple. It builds a tuple only if its format string contains two or more format units. If the format string is empty, it returns None; if it contains exactly one format unit, it returns whatever object is described by that format unit. To force it to return a tuple of size 0 or one, parenthesize the format string.
这意味着:如果您从至少两个元素构造一个元组,则无需担心:
Py_BuildValue("ii", a, b) # returns a tuple
Py_BuildValue("(ii)", a, b) # returns a tuple
如果只有一个元素就不一样了:
Py_BuildValue("i", a) # returns an integer
# parenthesized:
Py_BuildValue("(i)", a) # returns a tuple with an integer
或根本没有元素:
Py_BuildValue("") # returns None
# parenthesized:
Py_BuildValue("()") # returns an empty tuple.
所以只要确保格式字符串中有括号,返回值将是一个元组。