Cstring中的Swiftstring长度正确,但内容不正确
我对这个人有类似的问题,但问题不是这个答案的原因。
我得到一个C函数的const char *
。 这个函数实际上是在C ++中实现的,它返回一个结构体的值,它包含了std::string c_str()
的返回值,它是一个指向string内容的C指针。 这个string存在于静态内存中。 由于指针被复制到返回,我希望数据是好的。
根据Xcode的debugging器,我得到的string实际上是正确的长度(请参阅下面的countAndFlags
,正确的字符数为7),但内容是垃圾。 这是在一个UITableView方法,有什么奇怪的是,如果我使用reloadData()
TableView方法(我连线到一个button),然后有下面的name
variables的有效内容垃圾问题消失。 然而,这个随后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.name
的ss.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代码正常工作。