开发者社区> 问答> 正文

传递NULL结尾的字符串给C函数库

你要写一个扩展模块,需要传递一个NULL结尾的字符串给C函数库。 不过,你不是很确定怎样使用Python的Unicode字符串去实现它。

展开
收起
哦哦喔 2020-04-17 18:14:56 3250 0
2 条回答
写回答
取消 提交回答
  • 有点尴尬唉 你要寻找的东西已经被吃掉啦!

    传递NULL结尾的字符串给C函数库:可以参考这篇文章: https://www.baidu.com/link?url=6djl4oF9q-bjXsKIc7n5xA5eoO3YbD_ISURCaytWx9o0B2dmmEhXclgxb_R

    2020-04-17 23:56:56
    赞同 展开评论 打赏
  • 许多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字节。 因此,如果这个很重要的话,那你需要自己去做检查了。
    
    讨论
    
    2020-04-17 18:15:05
    赞同 展开评论 打赏
问答分类:
问答地址:
问答排行榜
最热
最新

相关电子书

更多
低代码开发师(初级)实战教程 立即下载
冬季实战营第三期:MySQL数据库进阶实战 立即下载
阿里巴巴DevOps 最佳实践手册 立即下载