2014-11-21 59 views
10

我發現下面的代碼編譯和工作原理:字符串值UnsafePointer <UInt8>功能參數的行爲

func foo(p:UnsafePointer<UInt8>) { 
    var p = p 
    for p; p.memory != 0; p++ { 
     print(String(format:"%2X", p.memory)) 
    } 
} 

let str:String = "今日" 
foo(str) 

這將打印E4BB8AE697A5那就是今日

一個有效的UTF8表示,據我所知,這是無證的行爲。從the document:

當一個函數被聲明爲接受一個UnsafePointer參數,它可以接受任何以下的:

  • 零,這是作爲一個空指針
  • 一種UnsafePointer,UnsafeMutablePointer通過,或AutoreleasingUnsafeMutablePointer值,必要時將其轉換爲UnsafePointer
  • 一個輸入表達式,其操作數類型爲Type的左值,該值作爲左值的地址傳遞
  • A [類型]值,其作爲一個指針數組的開始,並通過壽命延長的用於呼叫

的持續時間在此情況下,str是非它們。

我錯過了什麼嗎?


新增:

如果參數類型是UnsafePointer<UInt16>

func foo(p:UnsafePointer<UInt16>) { 
    var p = p 
    for p; p.memory != 0; p++ { 
     print(String(format:"%4X", p.memory)) 
    } 
} 
let str:String = "今日" 
foo(str) 
//^'String' is not convertible to 'UnsafePointer<UInt16>' 

即使內部String表示是UTF-16

let str = "今日" 
var p = UnsafePointer<UInt16>(str._core._baseAddress) 
for p; p.memory != 0; p++ { 
    print(String(format:"%4X", p.memory)) // prints 4ECA65E5 which is UTF16 今日 
} 
+0

它似乎是最後一個,不是? – Mundi 2014-11-21 14:30:29

+0

我認爲,沒有。'String'不是'Array ' – rintaro 2014-11-21 14:32:43

+0

我打算說倒數第二個。它就像一個輸入變量。或許「通過」**的措詞不清楚。這可能意味着「這是函數如何解釋這個論點」(我認爲是這個意思),或者「這就是你必須通過的」(我認爲這裏不是這個意思)。 – Mundi 2014-11-21 14:35:58

回答

7

這不工作正在工作,因爲e是Swift團隊自首次發佈以來所做的互操作性更改之一 - 你說得對,它看起來還沒有寫入文檔。 String需要UnsafePointer<UInt8>才能在不需要額外工作的情況下調用預計參數爲const char *的C函數。

看看C函數strlen,在 「shims.h」 定義:

size_t strlen(const char *s); 

在斯威夫特談到過,因爲這:

func strlen(s: UnsafePointer<Int8>) -> UInt 

可以稱之爲一個String沒有額外的工作:

let str = "Hi." 
strlen(str) 
// 3 

看看在這個答案的修訂,看到h ow C-string interop已經隨着時間而改變:https://stackoverflow.com/a/24438698/59541

+0

謝謝!不錯。根據'swiftc -emit-sil'輸出,它實際上是從'String.UTF8View.Generator'臨時創建'Array '。它看起來*不*那麼快... – rintaro 2014-11-21 18:29:45

+0

唉。那麼,SIL中的「I」代表中間值,對吧?這取決於編譯後的運行時如何實際實現字符串(如果它們只是'char *'的底層呢?),這可能是無效的。 – 2014-11-21 18:33:35

相關問題