【问题标题】:TypeError: argument of type 'char const *'TypeError: 'char const *' 类型的参数
【发布时间】:2014-01-21 05:51:28
【问题描述】:

我目前正在使用 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?

【问题讨论】:

  • active_call的类型是什么?如果是 unicode,那么cmd 将是 Unicode 字符串,str(cmd) 会将其转换为字符串。您可以在con.api 调用之前插入import pdb; pdb.set_trace() 行,然后检查cmd
  • active_call 很可能是 unicode,确实(来自 Django 数据库),但此错误消息中没有任何内容让我想到 unicode:你认为它可能相关吗?
  • 这肯定是相关的:API 很可能是通过一个只知道如何将 Python 字符串对象转换为 char const * 的接口构建框架导出的(通过在对象上调用 PyString_AsString)。 Python 2 Unicode 字符串不包含 C 字符——它们由 wchar_t 组成,这意味着它们不能简单地“转换”为 const char *,它们需要转换为必须分配的新缓冲区,等等。在 Python 中将 Unicode 字符串预转换为字符串,在对象到达 C 之前执行最困难的部分。
  • Mhmmm,这与 FS 的一些 python 文件一致,提到 SWIG (swig.org),它将自己描述为 一个连接的软件开发工具用各种高级编程语言用 C 和 C++ 编写的程序。还有一些我不知道的事情,比如char const *C charwchar_t,但我认为您的评论绝对值得回答。如果您有心情,请随时提供更多技术细节;)(另外我会在我的问题中添加细节)
  • 我不知道您不了解 C 基础知识。 :) 我现在添加了一个答案,详细解释了这一点。

标签: python freeswitch


【解决方案1】:

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

长答案:

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

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

例如,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 来检索每个Python 字符串存储的内部C 字符串,并且是strlen 所期望的。要使此代码也支持 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,但从链接的报告中不清楚他们是否进入。

【讨论】:

    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-12-16
      • 2016-05-19
      • 2020-01-20
      • 1970-01-01
      • 1970-01-01
      • 2023-04-08
      • 2014-07-03
      • 2021-08-06
      相关资源
      最近更新 更多