【问题标题】:Passing byte string from Python to C将字节字符串从 Python 传递到 C
【发布时间】:2020-05-28 13:31:23
【问题描述】:

我正在用 C 语言编写一个 python 扩展,并试图将一个字节对象传递给我的函数。显然,'s' 标记是用于字符串的;我试过'O'、'N'和其他一些没有运气的人。有没有可以用来解析字节对象的令牌?如果没有,是否有其他方法来解析字节对象?

static PyObject *test(PyObject *self, PyObject *args)
{
    char *dev;
    uint8_t *key;

    if(!PyArg_ParseTuple(args, "ss", &dev, &key))
        return NULL;

    printf("%s\n", dev);

    for (int i = 0; i < 32; i++)
    {
          printf("Val %d: %d\n", i, key[i]);
    }

    Py_RETURN_NONE;
}

从 python 调用:test(b"device", f.read(32)).

【问题讨论】:

  • 如果您使用 Python 3,则 test 函数调用中的第一个参数是 unicode 字符串,而不是字节字符串。你需要改写b"device"
  • 不,第一个参数应该是包含设备名称的 Unicode 字符串。第二个参数是从文件中作为字节对象读取的加密密钥。

标签: python c python-3.x python-c-api python-extensions


【解决方案1】:

如果您阅读parsing format string docs,就很清楚了。

s 仅用于从 str 对象获取NUL 终止的 UTF-8 编码 C 样式字符串(因此它适用于您的第一个参数,但不适用于您的第二个参数)。

y* 在文档中特别标注为(原文强调):

这是接受二进制数据的推荐方式。

y# 也可以工作,但代价是要求调用者提供不可变的 bytes 类对象,不包括 bytearraymmap.mmaps 之类的对象。

【讨论】:

  • 首先,这回答了我的问题;但是,它在循环后以Process finished with exit code 139 (interrupted by signal 11: SIGSEGV) 终止。您有什么快速的理由吗?
  • @DanielCopley:循环之后?如果您在输入数组的范围之外读取,您编写的代码可能会出现段错误,但这不太可能。不过,我不知道使用缓冲区后发生了什么变化;您基本上是在这里要求进行心理调试。段错误意味着您尝试读取或写入未映射到您的内存空间的地址,但它并没有说明太多。
  • 我想我可能错误地使用了Py_buffer 类型?我将y* 切换为y(它返回一个字符指针而不是Py_buffer),这似乎解决了我的问题。不确定这种方法是否存在任何缺陷。
  • @DanielCopley:原始二进制数据容易包含NUL 字节。如果不使用y*y#,则不知道数据的实际长度是多少,并且可能在到达末尾之前停止。
  • @DanielCopley:“肯定地知道长度”并弄错这一事实意味着您存在段错误或产生完全的乱码,而不是能够提出有用的异常是一个问题。在您依赖调用者数据的那一刻,您不应该在编写代码时做出可能导致程序崩溃而没有有用的诊断的假设。这也会误导维护者,他们可以并且会合理地假设 y 的意思是“NUL-终止的字节字符串”,因为这是它的唯一合法用途。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-10-10
  • 1970-01-01
  • 2012-02-12
  • 1970-01-01
  • 2014-02-24
  • 2010-10-26
  • 2021-08-13
相关资源
最近更新 更多