Swift 中 String 與 CChar 陣列的轉換

發表於2015-10-13

在現階段Swift的編碼中,我們還是有很多場景需要呼叫一些C函式。在Swift與C的混編中,經常遇到的一個問題就是需要在兩者中互相轉換字串。在C語言中,字串通常是用一個char陣列來表示,在Swift中,是用CChar陣列來表示。從CChar的定義可以看到,其實際上是一個Int8型別,如下所示:

如果我們想將一個String轉換成一個CChar陣列,則可以使用String的cStringUsingEncoding方法,它是String擴充套件中的一個方法,其宣告如下:

引數指定的是編碼格式,我們一般指定為NSUTF8StringEncoding,因此下面這段程式碼:

其輸出結果是:

可以看到”個”字由三個位元組表示,這是因為Swift的字串是Unicode編碼格式,一個字元可能由1個或多個位元組組成。另外需要注意的是CChar陣列的最後一個元素是0,它表示的是一個字串結束標誌符\n。

我們知道,在C語言中,一個陣列還可以使用指標來表示,所以字串也可以用char *來表示。在Swift中,指標是使用UnsafePointer或UnsafeMutablePointer來包裝的,因此,char指標可以表示為UnsafePointer<CChar>,不過它與[CChar]是兩個不同的型別,所以以下程式碼會報編譯器錯誤:

不過有意思的是我們可以直接將String字串傳遞給帶有UnsafePointer<CChar>引數的函式或方法,如以下程式碼所示:

而String字串卻不能傳遞給帶有[CChar]引數的函式或方法,如以下程式碼會報錯誤:

實際上,在C語言中,我們在使用陣列引數時,很少以陣列的形式來定義引數,則大多是通過指標方式來定義陣列引數。

如果想從[CChar]陣列中獲取一上String字串,則可以使用String的fromCString方法,其宣告如下:

從註釋可以看到,它會將UTF-8資料拷貝以新字串中。如下示例:

這裡需要注意的一個問題是,CChar陣列必須以0結束,否則會有不可預料的結果。在我的Playground示例程式碼中,如果沒有0,報了以下錯誤:

還有可能出現的情況是CChar陣列的儲存區域正好覆蓋了之前某一物件的區域,這一物件有一個可以表示字串結尾的標識位,則這時候,str2輸出的可能是”cde1一”。

小結

在Swift中,String是由獨立編碼的Unicode字元組成的,即Character。一個Character可能包括一個或多個位元組。所以將String字串轉換成C語言的char *時,陣列元素的個數與String字元的個數不一定相同(即在Swift中,與str.characters.count計算出來的值不一定相等)。這一點需要注意。另外還需要注意的就是將CChar陣列轉換為String時,陣列最後一個元素應當為字串結束標誌符,即0。

參考

  1. UTF8String
  2. String Structure Reference
  3. The Swift Programming Language中文版

相關文章