<p>简而言之:<code>cmd</code>可能包含一个Unicode字符串,不能简单地将其转换为<code>const char *</code>。错误消息可能来自包装器框架,该框架自动为C库(如SWIG或ctypes)编写Python绑定。该框架知道如何处理字节字符串,但对Unicode字符串进行punt操作。传递<code>str(cmd)</code>有帮助,因为它将Unicode字符串转换为字节字符串,从中可以轻松提取C代码所需的<code>const char *</code>值。</p>
<p>长答案:</p>
<p>C类型<code>char const *</code>,通常拼写为<code>const char *</code>,可以读取为“只读的<code>char</code>数组,<code>char</code>是C拼写“byte”的方式。当C函数接受<code>const char *</code>时,它需要一个“C字符串”,即以空字符结尾的<code>char</code>值数组。方便的是,Python字符串在内部表示为C字符串,并带有一些附加信息,如类型、引用计数和字符串长度(因此可以以O(1)的复杂度检索字符串长度,并且字符串本身可能包含空字符)。</p>
<p>Python 2中的Unicode字符串表示为<code>Py_UNICODE</code>数组,其宽度为16位或32位,具体取决于操作系统和构建时标志。这样的数组不能传递给需要8位字符数组的代码-它需要<em>转换</em>,通常需要转换为临时缓冲区,并且在不再需要时必须释放该缓冲区。</p>
<p>例如,对于C函数<code>strlen</code>,一个简单的(而且非常不必要的)包装可能如下所示:</p>
<pre><code>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);
}
</code></pre>
<p>代码只需调用<code>PyString_AsString</code>来检索由每个Python字符串存储并由<code>strlen</code>预期的内部C字符串。为了使此代码也支持Unicode对象(如果在Unicode对象上调用<code>strlen</code>甚至是有意义的话),它必须显式地处理它们:</p>
<pre><code>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);
}
</code></pre>
<p>注意额外的复杂性,不仅在样板代码行中,而且在不同的代码路径中,它们需要对保存Unicode字符串字节表示的临时对象进行不同的管理。还要注意的是,在将Unicode字符串转换为字节字符串时,决定使用<em>编码</em>所需的代码。UTF-8可以保证对任何Unicode字符串进行编码,但是将UTF-8编码的序列传递给需要C字符串的函数在某些情况下可能没有意义。<code>str</code>函数使用ASCII编解码器对Unicode字符串进行编码,因此,如果Unicode字符串实际包含任何非ASCII字符,则会出现异常。</p>
<p>已经有了<a href="http://sourceforge.net/p/swig/feature-requests/75/" rel="nofollow">requests to include this functionality in SWIG</a>,但是从链接的报告中还不清楚他们是否加入了。</p>