【问题标题】:Python ctypes returned c_char_p is corruptedPython ctypes 返回的 c_char_p 已损坏
【发布时间】:2021-11-06 10:35:06
【问题描述】:

我有一个包含以下内容的 C++ 接口:

extern "C"
{
     char const* getValForEntry(Entry e)
     {
         std::string no_val = "__err::no_val";
         if (handles.find(e) != handles.end())
         {
             std::string val = handles[e]->get_value();
             return val.c_str();
         }
         else
             return no_entry.c_str();
     }
}

我有一个 python 应用程序使用 ctypes 连接到这个接口,如下所示:

self.lib.getUpdateForEntry.restype = c_char_p
val = self.lib.getUpdateForEntry(e)

接口返回字符串:

{"RVC HR1":{"Mode":1,"Seq Num":162,"Home":7,"Time":"Thu Sep 01 10:00:00 2000","Flags":0,"Data Len":1024,"Data":[26, ... an array of 1024 values ... ,239]}}

python 应用看到的是:

p??"Mode":1,"Seq Num":162,"Home":7,"Time":"Thu Sep 01 10:00:00 2000","Flags":0,"Data Len":1024,"Data":[26, ... an array of 1024 values ... ,239]}}

消息应该是一个包含 2844 个字符的字符串,但在 python 中,前 12 个字符总是损坏,我看到消息:

'utf8' codec can't decode byte 0xb1 in position 1: invalid start byte

如果我将消息调整为数组中只有少数几个值(小于 10),那么消息很好,但是当我添加更多值时,消息的第一部分会损坏。有谁知道我为什么看到这个?是否有最大 c_char_p 长度,还是作为 ascii 返回并转换为 unicode?是别的吗?

【问题讨论】:

  • std::string val 是一个局部变量。当函数返回时,它将超出范围并变为无效。 return val.c_str(); 返回一个指向 val 拥有的缓冲区的指针,并且当函数返回时将与 val 的其余部分一起消失。它就在这里。
  • 该问题与 python 无关,与 C++ 中的局部变量有关,其范围仅限于声明它们的块。如果调用者是 C++,则可能会观察到类似的行为。
  • @Austin -- 如果这是真的,为什么消息是正确的 -- 欢迎来到 C++ 和未定义行为的世界。无论您观察什么,代码都不正确。更改编译器、编译器设置等,可能会得到不同的结果(可能会崩溃)。
  • 很难说为什么这个看起来很有效。也许是短字符串优化,并且在堆栈上的字符串的前几个字节上没有写入任何内容。也许系统正在保留一些动态分配的存储,因为它怀疑您很快就会再次需要它。任何可能的原因,这是未定义确切行为的重要原因之一。
  • 另外,我建议您识别代码错误,并在返回字符数据时采用不同的方法。花费(IMO,浪费)时间来尝试对未定义的行为进行推理并不是对开发资源的良好利用。

标签: python c++ string character-encoding ctypes


【解决方案1】:

有关说明,请参见上面的 PaulMcKenzie 和 user4581301 cmets。局部变量 val 超出范围,导致未定义的行为。

【讨论】:

    猜你喜欢
    • 2010-12-24
    • 2019-05-16
    • 1970-01-01
    • 1970-01-01
    • 2021-01-12
    • 2014-07-14
    • 1970-01-01
    • 1970-01-01
    • 2021-05-11
    相关资源
    最近更新 更多