我遇到了与 this fellow 类似的问题,但问题与该答案中的原因不同。
我正在从 C 函数中获取 const char *
。这个函数实际上是用 C++ 实现的,它按值返回一个结构,其中包含 std::string c_str()
的返回值,这是一个指向字符串内容的 C 指针。这个字符串存在于静态内存中。由于指针被复制到返回值中,我希望数据没有问题。
根据 Xcode 的调试器,我返回的字符串实际上是我预期的正确长度(参见下面的 countAndFlags
,正确的字符数为 7),但内容是垃圾。这是在 UITableView 方法中,非常奇怪的是,如果我使用 reloadData()
TableView 方法(我已将其连接到按钮),垃圾问题就会消失,然后该方法具有有效的内容name
下面的变量。然而,此 reloadData()
的后续调用不会改变表中其他地方使用的任何数据,只是这个有问题的字符串垃圾消失了。
这是第一次调试,显示垃圾但长度正确:
下面是文本正确时的下一遍:
我无法理解这种行为。结构 s
包含返回时未损坏的其他属性,但此 char *
仅在第一次传递时是垃圾,但长度仍然正确。
对于此处发生的事情的任何指示(无双关语意),我将不胜感激。
最后,这是返回 C 字符串的函数的 C++ 代码:
scene getScene(sceneID s){
static std::map<sceneID, std::vector<nodeID> > nodeArrays;
auto ss = globalObjects.scenes.at(s);
auto sceneroots = ss.roots;
if (nodeArrays.count(s)>0) nodeArrays.at(s).clear();
else confirmInsertion(nodeArrays.emplace(s, std::vector<nodeID>{}));
auto v = nodeArrays.at(s);
v.reserve(sceneroots.size());
for (const auto&i:sceneroots) v.push_back(i);
scene sr;
sr.name=ss.name.c_str();
sr.roots=vec2array(v);
return sr;
}
如果我记录 sr.name
它总是正确的。
这是场景
:
typedef struct {
const char* name;
arrayID roots;
} scene;
最佳答案
您应该注意的一个问题是在 C++ 函数中:
鉴于这是您的场景
定义:
typedef struct {
const char* name;
arrayID roots;
} scene;
在 getScene
C++ 函数中,您这样做:
auto ss = globalObjects.scenes.at(s);
然后你稍后再做这个:
scene sr;
sr.name = ss.name.c_str();
//...
return sr;
问题是因为 ss
是局部变量,分配给 sr.name
的 ss.name.c_str()
指针将函数返回时无效。访问此指针会导致未定义的行为。
该问题的一个解决方法是将字符串的内容复制到客户端程序发送的缓冲区,或者将内容复制到您知道客户端可用且不会失效的缓冲区。由于我不了解 Swift,您将不得不协商如何完成此操作。
另一个解决方案是确保您正在访问相同的 std::string
,而不是 std::string
的拷贝:
auto& ss = globalObjects.scenes.at(s);
现在返回对场景
的引用。但是当您稍后在应用程序中实际引用返回的 c_str()
值时,您会遇到确保 scene
中的字符串根本没有发生变化的问题. C++ 程序员不会长时间保留 c_str()
的返回值,因为这会导致难以诊断的错误。
底线是始终怀疑返回字符指针作为返回字符串数据的方式。 API 返回字符串数据的通常方式是让客户端提供一个缓冲区,然后 API 用字符串数据填充缓冲区,或者不太可能,API 分配内存并返回指向已分配内存的指针(这会导致复杂情况,如API 必须通过某种方式释放内存以避免内存泄漏。
关于c++ - 来自 C String 的 Swift String 的长度正确但内容不正确,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37776867/