在可变参数列表中将Swift字符串作为C字符串传递

时间:2016-07-21 17:25:38

标签: c swift

我正在尝试使用旧的printf样式字符串格式化程序从旧的Swift字符串定义新的Swift字符串。

我注意到只要我从Swift字符串文字开始,但不是字符串变量,这样就可以正常工作。

// OK!
String(format:"%s", "hello world".cStringUsingEncoding(NSUTF8StringEncoding))

// ERROR:  argument type '[CChar]?' does not conform to expected type 'CVarArgType'
let s = "hello world"
String(format:"%s", s.cStringUsingEncoding(NSUTF8StringEncoding))

为什么会这样?

什么是最好的解决方法?

(请注意我知道但不想使用Cocoa字符串格式化程序%@。我想要printf样式的格式化代码,因为我实际上要做的就是快速完成使用%-10s等代码进行脏表格对齐。)

这个问题涉及Swift 2.2。

2 个答案:

答案 0 :(得分:1)

不要仅为对齐创建C字符串。对此有一种方法stringByPaddingToLength

// Swift 2
s.stringByPaddingToLength(10, withString: " ", startingAtIndex: 0)

// Swift 3
s.padding(toLength: 10, withPad: " ", startingAt: 0)

请注意,如果字符串超过10个UTF-16代码单元,它将截断该字符串。

问题在于,Swift中有两个名为cStringUsingEncoding的方法:

  1. func cStringUsingEncoding(encoding: UInt) -> UnsafePointer<Int8>,作为NSString的方法
  2. func cStringUsingEncoding(encoding: NSStringEncoding) -> [CChar]?,作为String
  3. 的扩展

    如果我们想要一个指针,我们需要确保我们使用的是NSString,而不是String。

    在第一个示例中,字符串文字可以是String或NSString,因此编译器选择NSString,因为另一个不起作用。

    但在第二个示例中,s的类型已设置为String,因此选择返回[CChar]?的方法。

    这可以通过强制s成为NSString来解决这个问题:

    let s: NSString = "hello world"
    String(format:"%s", s.cStringUsingEncoding(NSUTF8StringEncoding))
    

答案 1 :(得分:0)

kennytm的回答显然是最好的方式。

但是对于那些仍然想知道如何以错误的方式执行操作并且无需通过NSString即可访问基于Swift String的c字符串的其他人,这似乎也有效(Swift 2.2):

var s:String  = "dynamic string"
s.nulTerminatedUTF8.withUnsafeBufferPointer { (buffptr) -> String in
  let retval:String = String(format:"%s",buffptr.baseAddress)
  return retval
}