在 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);

作为

暴露给 Swift
func 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&lt;CChar&gt; 创建一个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&lt;CChar&gt;,它必须传递给 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; . 好吧,废话。错误报告时间——不应该是从CStringUnsafePointer&lt;CChar&gt; 的单向转换。 reinterpretCast() 完美运行,我可以在这里应用它:***.com/a/24290234/1187415。再次感谢!【参考方案2】:

Swift 中的 String 结构有一个 init 例程,您可以像这样使用:

let myString = String(cString: myUnsafePointer)

另见init(cString: UnsafePointer)

【讨论】:

以上是关于在 Swift 中使用 C 字符串,或者:如何将 UnsafePointer<CChar> 转换为 CString的主要内容,如果未能解决你的问题,请参考以下文章

C语言调用Swift方法并传参数

如何将 Swift 字符串数组传递给采用 char ** 参数的 C 函数

如何将 Swift 数组转换为字符串?

如何在目标 C 和 swift Viewcontroller 中使用委托

将 Swift 字符串数组转换为 C 字符串数组指针

将 Swift 字符串数组转换为 C 字符串数组指针