在Swift中使用C字符串,或者:如何将UnsafePointer <CChar>转换为CString

Mar*_*n R 26 cstring swift

在Swift中使用标准C库函数时,我在传递C字符串时遇到了问题.作为一个简单的例子(仅用于演示问题),标准C库函数

char * strdup(const char *s1);
Run Code Online (Sandbox Code Playgroud)

接触Swift作为

func strdup(_: CString) -> UnsafePointer<CChar>
Run Code Online (Sandbox Code Playgroud)

这意味着返回值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
Run Code Online (Sandbox Code Playgroud)

我的问题是:如何CString从a 创建一个Swift UnsafePointer<CChar>,以便一个标准库函数返回的C字符串可以传递给另一个函数?

我能找到的唯一方法是(使用Swift语言中如何将字符串转换为CString的代码):

let s2a = String.fromCString(s2).bridgeToObjectiveC().UTF8String
let s3 = strdup(s2a)
Run Code Online (Sandbox Code Playgroud)

但我认为这并不令人满意,原因有两个:

  • 对于简单的任务来说太复杂了.
  • (主要原因:)上述转换仅在C字符串是有效的UTF-8字符串时有效,否则失败并出现运行时异常.但是C字符串是一个任意 字符序列,由NUL字符分隔.

备注/背景:当然,使用Swift String或Objective-C 等高级数据结构的高级函数NSString更可取.但是标准C库中有BSD功能,它们在Foundation框架中没有完全对应的功能.

我在尝试回答Swift中的Accessing临时目录时遇到了这个问题.这里mkdtemp()是一个没有确切NSFileManager替换的BSD函数(据我所知). 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
Run Code Online (Sandbox Code Playgroud)

Nat*_*ook 18

Swift 1.1(或许更早)有更好的C字符串桥接:

let haystack = "This is a simple string"
let needle = "simple"
let result = String.fromCString(strstr(haystack, needle))
Run Code Online (Sandbox Code Playgroud)

CString类型是完全消失.


Ale*_*usa 5

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

let myString = String(cString: myUnsafePointer)
Run Code Online (Sandbox Code Playgroud)

另请参见init(cString: UnsafePointer)