SwiftのStringからCの文字列を生成するベスト・プラクティス

```title:検証環境
Apple Swift version 4.1 (swiftlang-902.0.48 clang-902.0.37.1)
Target: x86_64-apple-darwin17.6.0
```

# TL;DR;

SwiftのStringからC用の文字列を生成するには、`utf8CString` プロパティから生成するのがベスト・プラクティスだと思われます。

# SwiftにおけるC文字列を表す型

SwiftにてUTF8用のCの文字列を表す型は以下があります。

* UnsafePointer\<CChar>
* UnsafeMutablePointer\<CChar>
* UnsafePointer\<UInt8>
* UnsafeMutablePointer\<UInt8>

**Note:**  CChar = Int8

Foundationを使わずに、上記の型を生成するためのベスト・プラクティスを考えてみました。

# StringからC文字列への変換に使用するプロパティ

Cの文字列には終端を意味する **null文字** を最後につける必要があります。

しかしながら、 **utf8** プロパティで生成される `String.UTF8View` の要素内には、null文字が含まれません。
なのでnull終端文字が含まれる **utf8CString** プロパティを使用します。

[utf8](https://developer.apple.com/documentation/swift/string/1539703-utf8) 

```swift:utf8.swift
let s = "Hello!"
let bytes = Array(s.utf8)
print(bytes) 
// Prints "[72, 101, 108, 108, 111, 33]"
```

[utf8CString](https://developer.apple.com/documentation/swift/string/2430818-utf8cstring)

```swift:utf8cstring.swift
let s = "Hello!"
let bytes = s.utf8CString
print(bytes)
// Prints "[72, 101, 108, 108, 111, 33, 0]" 最後にnull終端文字の０が含まれる
```

# String to cString

## UnsafeMutablePointer\<CChar> の生成

`utf8CString` プロパティで生成される配列の要素の型が `CChar` なので、配列をそのままUnsafePointerに変換して生成します。

**Note:**  CChar = Int8

```swift:string2cstring_int8.swift
func makeCString(from str: String) -> UnsafeMutablePointer<Int8> {
    let count = str.utf8CString.count 
    let result: UnsafeMutableBufferPointer<Int8> = UnsafeMutableBufferPointer<Int8>.allocate(capacity: count)
    // func initialize<S>(from: S) -> (S.Iterator, UnsafeMutableBufferPointer<Element>.Index)
    _ = result.initialize(from: str.utf8CString)
    return result.baseAddress!
}

// EXAMPLE
let str = "朝日がさんさん　おはよ〜お〜さ〜ん 🌟 Good morning everyone! 👪"
let cstr = makeCString(from: str)
let restr = String(cString: cstr)
print(str == restr) // true
```


## UnsafeMutablePointer\<UInt8> の生成

**utf8cstring** で生成される配列の要素の型が **CChar**  なので、 `withMemoryRebound` メソッドを使って、要素の中身を **UInt8** にキャストします。

**Note:**  CChar = Int8

```swift:string2cstring_uint8.swift
func makeCString(from str: String) -> UnsafeMutablePointer<UInt8> {
    let utf8 = str.utf8CString
    let count = utf8.count 

    let result = UnsafeMutableBufferPointer<UInt8>.allocate(capacity: count)
    _ = utf8.withUnsafeBufferPointer { baseAddress in
        
        // 要素の中身を CChar から UInt8 にキャストする 
        baseAddress.withMemoryRebound(to: UInt8.self) { baseAddress2 in
            
            // baseAddress2: UnsafeMutableBufferPointer<UInt8> 
            result.initialize(from: baseAddress2)
        }
    }
    return result.baseAddress!
}
```

## Appendix utf8プロパティからの生成

**utf8** プロパティからC文字列を生成する場合は、null文字を追加すれば問題ありません。

```swift:string2cstring.swift
// UnsafeMutablePointer<UInt8>
func makeCString(from str: String) -> UnsafeMutablePointer<UInt8> {
    var utf8 = Array(str.utf8)
    utf8.append(0)  // adds null character
    let count = utf8.count
    let result = UnsafeMutableBufferPointer<UInt8>.allocate(capacity: count)
    _ = result.initialize(from: utf8)
    return result.baseAddress!
}

// UnsafeMutablePointer<Int8>
func makeCString(from str: String) -> UnsafeMutablePointer<Int8> {
    var utf8 = Array(str.utf8)
    utf8.append(0)  // adds null character
    let count = utf8.count
    let result = UnsafeMutableBufferPointer<Int8>.allocate(capacity: count)
    utf8.withUnsafeBufferPointer { baseAddress in
        baseAddress.withMemoryRebound(to: Int8.self) { (baseAddress2) in
            _ = result.initialize(from: baseAddress2)
        }
    }
    return result.baseAddress!
}
```