Cstring中的Swiftstring长度正确,但内容不正确

我对这个人有类似的问题,但问题不是这个答案的原因。

我得到一个C函数的const char * 。 这个函数实际上是在C ++中实现的,它返回一个结构体的值,它包含了std::string c_str()的返回值,它是一个指向string内容的C指针。 这个string存在于静态内存中。 由于指针被复制到返回,我希望数据是好的。

根据Xcode的debugging器,我得到的string实际上是正确的长度(请参阅下面的countAndFlags ,正确的字符数为7),但内容是垃圾。 这是在一个UITableView方法,有什么奇怪的是,如果我使用reloadData() TableView方法(我连线到一个button),然后有下面的namevariables的有效内容垃圾问题消失。 然而,这个随后reloadData()调用不会改变表中其他地方使用的任何数据,只有这个有问题的string垃圾消失了。

在这里输入图像说明

这是第一遍debugging器,显示垃圾但正确的长度:

在这里输入图像说明

当文本是正确的时候,下一个通过:

在这里输入图像说明

我无法理解这种行为。 结构体包含其他属性,它们在返回时没有被破坏,但是这个char *只在第一次通过时是垃圾的,并且长度正确。

我很欣赏任何指针(没有双关语意)在这里发生的事情。

最后,这里是返回Cstring的函数的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; } 

如果我loggingsr.name它总是正确的。

这是scene

  typedef struct { const char* name; arrayID roots; } scene; 

你应该注意的一个问题是在C ++函数中:

鉴于这是你的scene定义:

 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是一个局部variables,当函数返回时,分配给sr.namess.name.c_str()指针将无效。 访问这个指针导致未定义的行为。

解决此问题的一个方法是将string的内容复制到由客户端程序发送的缓冲区,或者将内容复制到您知道客户端可用的缓冲区,并且不会失效。 由于我不知道斯威夫特,你将不得不谈判如何做到这一点。


另一个解决scheme是确保你正在访问相同的std::string ,而不是std::string的副本:

auto& ss = globalObjects.scenes.at(s);

现在返回到scene的引用。 但是,当你实际上在你的应用程序中引用了返回的c_str()值的时候,你有这个问题确保scene中的string没有被突变。 一个C ++程序员不会长时间保持c_str()的返回值,因为这会导致难以诊断的错误。


底线是总是怀疑返回字符指针作为返回string数据的手段。 API返回string数据的通常方式是让客户端提供一个缓冲区,并且API用string数据填充缓冲区,或者API不太可能分配内存并返回指向分配内存的指针(这会导致复杂性API必须通过一些手段释放内存以避免内存泄漏)。

在你调用String.fromCString的时候,你似乎正在传递一个有效的Cstring,这个string以后会失效。 正如你注意到的,Swiftstring是正确的长度,但是从debugging器你可以看到它embedded了\0 。 我能想到的唯一方法就是如果Cstring最初是有效的,然后在Swift完成parsing之前就被损坏了。

来自http://www.cplusplus.com/reference/string/string/c_str/

指针返回指向string对象当前使用的内部数组,以存储符合其值的字符。

通过进一步调用修改对象的其他成员函数,返回的指针可能会失效。

你应该在你的C ++代码中使用Cstring,以便知道它在那之后不会改变,然后你可以确认你的Swift代码正常工作。