【问题标题】:How to convert String to UnsafePointer<UInt8> and length如何将字符串转换为 UnsafePointer<UInt8> 和长度
【发布时间】:2014-08-28 17:47:57
【问题描述】:

当我使用NSOutputStreamwrite 方法时

func write(_ buffer: UnsafePointer<UInt8>, maxLength length: Int) -> Int

我不知道如何将String 转换为UnsafePointer&lt;UInt8&gt; 和长度

我怎样才能快速做到这一点?

【问题讨论】:

    标签: string swift


    【解决方案1】:

    您必须先将字符串转换为 UTF-8 数据

    let string = "foo bar"
    let data = string.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
    

    然后将其写入输出流

    let outputStream: NSOutputStream = ... // the stream that you want to write to
    let bytesWritten = outputStream.write(UnsafePointer(data.bytes), maxLength: data.length)
    

    UnsafePointer() 强制转换是必要的,因为 data.bytes 具有 UnsafePointer&lt;Void&gt; 类型,而不是 write() 所期望的 UnsafePointer&lt;UInt8&gt; 方法。


    Swift 3 更新:

    let string = "foo bar"
    // Conversion to UTF-8 data (cannot fail):
    let data = string.data(using: String.Encoding.utf8)! 
    
    // Write to output stream:
    let outputStream: NSOutputStream = ... // the stream that you want to write to
    let bytesWritten = data.withUnsafeBytes { outputStream.write($0, maxLength: data.count) }
    

    【讨论】:

    • 嗨 Martin,我如何将 Swift 字符串转换为 UnsafePointer&lt;UInt8&gt;?和UnsafePointer&lt;Void&gt;有什么不同吗?我发现有一个 UTF8 结构和一个 String.UTF8View 嵌套类型,但不知道如何使用它们。
    • @Isuru:我不确定我是否正确理解了您的问题。上面的代码首先将 Swift String 转换为NSData。还有一个withCString 方法产生UnsafePointer&lt;Int8&gt;
    • 简单地说,我有一个 String 类型的 Swift 变量。我需要将其转换为UnsafePointer&lt;UInt8&gt;
    • 是的,但是在您的答案和问题中都没有声明/实例化它,并且由于正确实例化输出流还有其他语义,因此您的答案是不完整的。
    • @Awesome-o:问题是如何将字符串转换为可以传递给 NSOutputStream 的 write 方法的东西,而不是如何创建一个 NSOutputStream。但我试图澄清 outputStream 是什么,感谢您的反馈。
    【解决方案2】:

    这是在 Swift 3 中的操作方法。在 Swift 4 中也可以正常运行

    extension String {
    
      func toPointer() -> UnsafePointer<UInt8>? {
        guard let data = self.data(using: String.Encoding.utf8) else { return nil }
    
        let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: data.count)
        let stream = OutputStream(toBuffer: buffer, capacity: data.count)
    
        stream.open()
        data.withUnsafeBytes({ (p: UnsafePointer<UInt8>) -> Void in
          stream.write(p, maxLength: data.count)
        })
    
        stream.close()
    
        return UnsafePointer<UInt8>(buffer)
      }
    }
    

    String 转换为UnsafeMutablePointer&lt;Int8&gt;

    let cString = strdup("Hello") // UnsafeMutablePointer<Int8>
    

    UnsafeMutablePointer&lt;Int8&gt; 转换为String

    let string = String(cString: cString!) // String
    

    【讨论】:

    • 重要的是要记住toPointer() 函数返回一个指向在堆上分配的内存的指针,因此,当你完成它以避免内存泄漏时,你应该free() 它。
    • 我想转换成 UnsafeMutablePointer,请帮忙
    【解决方案3】:

    斯威夫特 4

    将 String 转换为 NSString,然后使用 NSString 的方法。

    let text = "Hello"
    let pointer: UnsafePointer<Int8>? = NSString(string: text).utf8String
    let length = NSString(string: text).length
    

    【讨论】:

      【解决方案4】:

      您也可以让 Swift 为您代劳!

      import Foundation
      
      // Example function:
      func printUTF8Vals(_ ptr: UnsafePointer<UInt8>, _ len: Int) { 
          for i in 0..<len { 
              print(ptr[i]) 
          } 
      } 
      
      // Call it:
      let str = "Hello"
      printUTF8Vals(str, str.lengthOfBytes(using: String.Encoding.utf8))
      
      // Prints:
      // 72
      // 101
      // 108
      // 108
      // 111
      

      【讨论】:

      • 为什么不只是str.utf8.count
      • 为了通过镜头?是的,这也应该工作!我试图说明您可以将 String 类型传递给期望 UnsafePointer 的函数,而无需任何显式转换
      【解决方案5】:

      现在使用 Swift 4 工作的人的答案。您不能再从 Data 对象中获取字节,您必须将它们复制到 UnsafeMutablePointer 中

      let helloWorld = "Hello World!"
      
      let data = helloWorld.data(using: String.Encoding.utf8, allowLossyConversion: false)!
      var dataMutablePointer = UnsafeMutablePointer<UInt8>.allocate(capacity: data.count)
      
      //Copies the bytes to the Mutable Pointer
      data.copyBytes(to: dataMutablePointer, count: data.count)
      
      //Cast to regular UnsafePointer
      let dataPointer = UnsafePointer<UInt8>(dataMutablePointer)
      
      //Your stream
      oStream.write(dataPointer, maxLength: data.count)
      

      【讨论】:

        【解决方案6】:

        这是 Swift 5 的字符串扩展,您可以将字符串转换为 UnsafePointer&lt;UInt8&gt;UnsafeMutablePointer&lt;Int8&gt;

        extension String {
            func toUnsafePointer() -> UnsafePointer<UInt8>? {
                guard let data = self.data(using: .utf8) else {
                    return nil
                }
        
                let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: data.count)
                let stream = OutputStream(toBuffer: buffer, capacity: data.count)
                stream.open()
                let value = data.withUnsafeBytes {
                    $0.baseAddress?.assumingMemoryBound(to: UInt8.self)
                }
                guard let val = value else {
                    return nil
                }
                stream.write(val, maxLength: data.count)
                stream.close()
        
                return UnsafePointer<UInt8>(buffer)
            }
        
            func toUnsafeMutablePointer() -> UnsafeMutablePointer<Int8>? {
                return strdup(self)
            }
        }
        

        UnsafeMutablePointer&lt;Int8&gt; 转换为String

        guard let mutablePointer = "test".toUnsafeMutablePointer() else {
            return
        }
        
        let str = String(cString: mutablePointer)
        

        【讨论】:

        【解决方案7】:

        迄今为止最简单的方法(在 Swift 5 中):

        let s = "hello, world"
        let pointer = UnsafePointer(Array(s.utf8CString))
        

        不确定它的向后兼容性如何。

        【讨论】:

        • 这失败了:无法将类型“UnsafePointer”(又名“UnsafePointer”)的返回表达式转换为返回类型“UnsafePointer
        • int8_t 实际上表示 char 并且 UnsafePointer 和 UnsafePointer 都是相同的,它们都签名为 int8。但是 UInt8 是 unsigned char 所以你需要将有符号转换为无符号来解决它。
        【解决方案8】:

        我看到还有其他答案,以及一个公认的答案,所以看来你已经得到了你需要的东西。我来到这里是因为我注意到 Swift 5 对 withUnsafeMutableBytes 等人的弃用警告,并开始测试 @abdullahselek 的答案,但我注意到在 Swift 5 中(尚未验证它是否在以前的版本中有效)String 可转换为UnsafePointer&lt;UInt8&gt; 内联,因此您可以在需要 UnsafePointer&lt;UInt8&gt; 的地方使用它。如果看到另一个例子有帮助,这里是我们旧的和更新的函数,张贴在这里:

        let derivationStatus = localDerivedKeyData.withUnsafeMutableBytes { derivedKeyBytes in
          salt.withUnsafeBytes { saltBytes in
        
            CCKeyDerivationPBKDF(
              CCPBKDFAlgorithm(kCCPBKDF2),
              password,
              passwordData.count,
              saltBytes,
              salt.count,
              algorithm,
              UInt32(rounds),
              derivedKeyBytes,
              derivedKeyData.count
            )
          }
        }
        

        let derivationStatus = localDerivedKeyData.withUnsafeMutableBytes { (outputBytes: UnsafeMutableRawBufferPointer) -> Int32 in
          let status = CCKeyDerivationPBKDF(
            CCPBKDFAlgorithm(kCCPBKDF2),
            password, // a String
            passwordData.count, // just the password String converted to Data
            String(data: salt, encoding: .utf8),  // converts salt (Data) to String
            salt.count,
            algorithm,
            UInt32(rounds),
            outputBytes.baseAddress?.assumingMemoryBound(to: UInt8.self),
            derivedKeyData.count
          )
          return status
        }
        

        话虽如此,您可以使用类似的方法来获取您的流,如下所示:

        let stream = OutputStream(toBuffer: UnsafeMutablePointer(mutating: someString), capacity: someString.data(using: .utf8)!.count)
        

        (! 用于消除编译器错误,但应尽可能避免强制展开)。

        【讨论】:

        • 嗨,localDerivedKeyData 的类型是什么?新代码中的输出变量是什么?和
        • localDerivedKeyDataDataderivationStatus 是一个 Int32,为您提供操作的输出状态。 localDerivedKeyData 通过此操作逐字节写入(假设它是一个具有适当长度的字节数组(数据),开始时为空)
        • 什么是函数抛出任何错误/异常,你能分享完整的函数吗?
        【解决方案9】:

        我已经创建了一个 Swift 扩展,其中包括了许多其他用于从字符串生成指针的功能。

        包括一个完整的测试套件,它支持:

        • myString.stackPointer() -&gt; UnsafePointer&lt;Int8&gt;?
        • myString.mutableStackPointer() -&gt; UnsafeMutablePointer&lt;Int8&gt;?
        • myString.withUnsignedStackPointer { (ptr: UnsafePointer&lt;UInt8&gt;?) in
        • myString.withUnsignedMutableStackPointer { (ptr: UnsafeMutablePointer&lt;UInt8&gt;?) in
        • myString.heapPointer() -&gt; UnsafePointer&lt;Int8&gt;?
        • myString.mutableHeapPointer() -&gt; UnsafeMutablePointer&lt;Int8&gt;?
        • myString.unsignedHeapPointer() -&gt; UnsafePointer&lt;UInt8&gt;?
        • myString.unsignedMutableHeapPointer() -&gt; UnsafeMutablePointer&lt;UInt8&gt;?

        https://gist.github.com/nathan-fiscaletti/892e074dc14e6707603414cd2d80c287

        如果您想对其进行测试,您应该可以直接将其粘贴到 Swift Playground 中。

        【讨论】:

          【解决方案10】:

          file.cString(使用:String.Encoding.utf8)

          【讨论】:

          • 添加一些错误说明以及此代码将更正的内容。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-06
          • 1970-01-01
          • 2013-10-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多