在 Swift 中使用 C 字符串,或者:如何将 UnsafePointer<CChar> 转换为 CString
Posted
技术标签:
【中文标题】在 Swift 中使用 C 字符串,或者:如何将 UnsafePointer<CChar> 转换为 CString【英文标题】:Working with C strings in Swift, or: How to convert UnsafePointer<CChar> to CString 【发布时间】:2014-08-16 14:57:58 【问题描述】:在 Swift 中使用标准 C 库函数时,我遇到了一些问题 当传递 C 字符串时。作为一个简单的例子(只是为了演示问题),标准 C 库函数
char * strdup(const char *s1);
作为
暴露给 Swiftfunc strdup(_: CString) -> UnsafePointer<CChar>
这意味着strdup()
的返回值不能传递给另一个strdup()
调用:
let s1 : CString = "abc"
let s2 = strdup(s1) // OK, s2 is a UnsafePointer<CChar>
let s3 = strdup(s2) // error: could not find an overload for '__conversion' that accepts the supplied arguments
我的问题是:如何从UnsafePointer<CChar>
创建一个Swift CString
,
以便将一个标准库函数返回的 C 字符串传递给另一个函数?
我能找到的唯一方法是(使用来自How do you convert a String to a CString in the Swift Language? 的代码):
let s2a = String.fromCString(s2).bridgeToObjectiveC().UTF8String
let s3 = strdup(s2a)
但我觉得这并不令人满意,原因有两个:
对于简单的任务来说太复杂了。 (主要原因:) 只有当 C 字符串是有效的 UTF-8 时,上述转换才有效 字符串,否则它会因运行时异常而失败。但是一个 C 字符串是一个 任意的 字符序列,由 NUL 字符分隔。备注/背景:当然,使用 Swift String
或 Objective-C NSString
等高级数据结构的高级函数更可取。但是里面有BSD功能
在 Foundation 框架中没有完全对应的标准 C 库。
我在尝试回答 Accessing temp directory in Swift 时遇到了这个问题。
这里,mkdtemp()
是一个 BSD 函数,不存在精确的 NSFileManager
替换
(据我所知)。
mkdtemp()
返回一个 UnsafePointer<CChar>
,它必须传递给
NSFileManager
函数 stringWithFileSystemRepresentation
接受 CString
论据。
更新: 从 Xcode 6 beta 6 开始,这个问题不再存在,因为 C-Strings 到 Swift 的映射已经被简化了。你可以写
let s1 = "abc" // String
let s2 = strdup(s1) // UnsafeMutablePointer<Int8>
let s3 = strdup(s2) // UnsafeMutablePointer<Int8>
let s4 = String.fromCString(s3) // String
【问题讨论】:
感谢匿名投票者提醒我更新问题:) 【参考方案1】:Swift 1.1(或者更早的版本)有更好的 C 字符串桥接:
let haystack = "This is a simple string"
let needle = "simple"
let result = String.fromCString(strstr(haystack, needle))
CString
类型完全消失了。
【讨论】:
嗨内特,感谢您的回复。st.withCString( $0 )
绝对比 bridgeToObjectiveC().UTF8String
更优雅。 - 但是如果up
不是有效的UTF-8 字符串,String.fromCString(up)
已经失败并出现运行时异常,所以这个问题没有解决。试试CStringFromUnsafeCChar(foo())
,其中foo()
是一个C 函数,它返回一个不是有效UTF-8 的C 字符串。例如:char *foo(void) static char buf[] = -1, 0; return buf;
.
好吧,废话。错误报告时间——不应该是从CString
到UnsafePointer<CChar>
的单向转换。
reinterpretCast()
完美运行,我可以在这里应用它:***.com/a/24290234/1187415。再次感谢!【参考方案2】:
Swift 中的 String 结构有一个 init 例程,您可以像这样使用:
let myString = String(cString: myUnsafePointer)
另见init(cString: UnsafePointer)
【讨论】:
以上是关于在 Swift 中使用 C 字符串,或者:如何将 UnsafePointer<CChar> 转换为 CString的主要内容,如果未能解决你的问题,请参考以下文章
如何将 Swift 字符串数组传递给采用 char ** 参数的 C 函数