你要写一个扩展模块,需要传递一个NULL结尾的字符串给C函数库。 不过,你不是很确定怎样使用Python的Unicode字符串去实现它。
传递NULL结尾的字符串给C函数库:可以参考这篇文章: https://www.baidu.com/link?url=6djl4oF9q-bjXsKIc7n5xA5eoO3YbD_ISURCaytWx9o0B2dmmEhXclgxb_R
许多C函数库包含一些操作NULL结尾的字符串,被声明类型为 char * . 考虑如下的C函数,我们用来做演示和测试用的:
void print_chars(char *s) {
while (*s) {
printf("%2x ", (unsigned char) *s);
s++;
}
printf("\n");
}
此函数会打印被传进来字符串的每个字符的十六进制表示,这样的话可以很容易的进行调试了。例如:
print_chars("Hello"); // Outputs: 48 65 6c 6c 6f
对于在Python中调用这样的C函数,你有几种选择。 首先,你可以通过调用 PyArg_ParseTuple() 并指定”y“转换码来限制它只能操作字节,如下:
static PyObject *py_print_chars(PyObject *self, PyObject *args) {
char *s;
if (!PyArg_ParseTuple(args, "y", &s)) {
return NULL;
}
print_chars(s);
Py_RETURN_NONE;
}
结果函数的使用方法如下。仔细观察嵌入了NULL字节的字符串以及Unicode支持是怎样被拒绝的:
>>> print_chars(b'Hello World')
48 65 6c 6c 6f 20 57 6f 72 6c 64
>>> print_chars(b'Hello\x00World')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: must be bytes without null bytes, not bytes
>>> print_chars('Hello World')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' does not support the buffer interface
>>>
如果你想传递Unicode字符串,在 PyArg_ParseTuple() 中使用”s“格式码,如下:
static PyObject *py_print_chars(PyObject *self, PyObject *args) {
char *s;
if (!PyArg_ParseTuple(args, "s", &s)) {
return NULL;
}
print_chars(s);
Py_RETURN_NONE;
}
当被使用的时候,它会自动将所有字符串转换为以NULL结尾的UTF-8编码。例如:
>>> print_chars('Hello World')
48 65 6c 6c 6f 20 57 6f 72 6c 64
>>> print_chars('Spicy Jalape\u00f1o') # Note: UTF-8 encoding
53 70 69 63 79 20 4a 61 6c 61 70 65 c3 b1 6f
>>> print_chars('Hello\x00World')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: must be str without null characters, not str
>>> print_chars(b'Hello World')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: must be str, not bytes
>>>
如果因为某些原因,你要直接使用 PyObject * 而不能使用 PyArg_ParseTuple() , 下面的例子向你展示了怎样从字节和字符串对象中检查和提取一个合适的 char * 引用:
/* Some Python Object (obtained somehow) */
PyObject *obj;
/* Conversion from bytes */
{
char *s;
s = PyBytes_AsString(o);
if (!s) {
return NULL; /* TypeError already raised */
}
print_chars(s);
}
/* Conversion to UTF-8 bytes from a string */
{
PyObject *bytes;
char *s;
if (!PyUnicode_Check(obj)) {
PyErr_SetString(PyExc_TypeError, "Expected string");
return NULL;
}
bytes = PyUnicode_AsUTF8String(obj);
s = PyBytes_AsString(bytes);
print_chars(s);
Py_DECREF(bytes);
}
前面两种转换都可以确保是NULL结尾的数据, 但是它们并不检查字符串中间是否嵌入了NULL字节。 因此,如果这个很重要的话,那你需要自己去做检查了。
讨论
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。