TypeError:'char const *'类型的参数

时间:2014-01-03 14:20:23

标签: python freeswitch

我目前正在与Freeswitch及其event socket library(通过mod event socket)合作。例如:

from ESL import ESLconnection

cmd = 'uuid_kill %s' % active_call # active_call comes from a Django db and is unicode
con = ESLconnection(config.HOST, config.PORT, config.PWD)
if con.connected():
    e = con.api(str(cmd))
else:
    logging.error('Couldn\'t connect to Freeswitch Mod Event Socket')

正如您所看到的,我必须使用con.api()明确地转换str()的参数。如果没有这个,调用将在以下堆栈跟踪中结束:

Traceback (most recent call last):
  [...]
    e = con.api(cmd)
  File "/usr/lib64/python2.7/site-packages/ESL.py", line 87, in api
    def api(*args): return apply(_ESL.ESLconnection_api, args)
TypeError: in method 'ESLconnection_api', argument 2 of type 'char const *'

我不明白这个TypeError:这是什么意思? cmd包含一个字符串,那么当我使用str(cmd)进行转换时,它是如何解决的? 它可能与通过SWIG生成的Freeswitch的python API有关吗?

2 个答案:

答案 0 :(得分:10)

简短回答:cmd可能包含一个Unicode字符串,该字符串无法轻易转换为const char *。错误消息可能来自一个包装器框架,它自动为C库编写Python绑定,例如SWIG或ctypes。框架知道如何处理字节字符串,但是在Unicode字符串上发挥作用。传递str(cmd)会有所帮助,因为它会将Unicode字符串转换为字节字符串,从中可以轻松地提取C代码所期望的const char *值。

答案很长:

C类型char const *,通常拼写为const char *,可以读作“char的只读数组”,char是C的拼写方式“字节”。当C函数接受const char *时,它需要一个“C字符串”,即以{null}字符结尾的char值数组。方便的是,Python字符串在内部表示为C字符串,带有一些附加信息,例如类型,引用计数和字符串的长度(因此可以使用O(1)复杂度检索字符串长度,并且还可以包含字符串空字符本身)。

Python 2中的Unicode字符串表示为Py_UNICODE的数组,它们是16位或32位宽,具体取决于操作系统和构建时标志。这样的数组不能传递给需要8位字符数组的代码 - 它需要转换,通常是临时缓冲区,并且必须在不再需要时释放该缓冲区。

例如,C函数strlen的一个简单(并且非常不必要)的包装器可能如下所示:

PyObject *strlen(PyObject *ignore, PyObject *obj)
{
  const char *c_string;
  size_t len;
  if (!PyString_Check(obj)) {
    PyErr_Format(PyExc_TypeError, "string expected, got %s", Py_TYPE(obj)->tp_name);
    return NULL;
  }
  c_string = PyString_AsString(obj);
  len = strlen(c_string);
  return PyInt_FromLong((long) len);
}

代码只需调用PyString_AsString来检索由strlen所需的每个Python字符串存储的内部C字符串。对于此代码也支持Unicode对象(假设它甚至在Unicode对象上调用strlen),它必须明确处理它们:

PyObject *strlen(PyObject *ignore, PyObject *obj)
{
  const char *c_string;
  size_t len;
  PyObject *tmp = NULL;
  if (PyString_Check(obj))
    c_string = PyString_AsString(obj);
  else if (PyUnicode_Check(obj)) {
    if (!(tmp = PyUnicode_AsUTF8String(obj)))
      return NULL;
    c_string = PyString_AsString(tmp);
  }
  else {
    PyErr_Format(PyExc_TypeError, "string or unicode expected, got %s",
                 Py_TYPE(obj)->tp_name);
    return NULL;
  }
  len = strlen(c_string);
  Py_XDECREF(tmp);
  return PyInt_FromLong((long) len);
}

注意额外的复杂性,不仅在样板代码行中,而且在需要对保存Unicode字符串的字节表示的临时对象进行不同管理的不同代码路径中。另请注意,在将Unicode字符串转换为字节字符串时,需要决定使用编码。 UTF-8保证能够编码任何Unicode字符串,但是将UTF-8编码的序列传递给期望C字符串的函数可能对某些用途没有意义。 str函数使用ASCII编解码器对Unicode字符串进行编码,因此如果Unicode字符串实际上包含任何非ASCII字符,则会出现异常。

已经有requests to include this functionality in SWIG,但链接报告中是否有明确说明它是否已经显示。

答案 1 :(得分:2)

我有类似的问题,我通过这样做解决了这个问题: cmd = 'uuid_kill %s'.encode('utf-8')