【发布时间】: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