欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
在Swift中使用遺留的C API
 
2015-01-13 20:48:32http://www.sitepoint.com/using-legacy-c-apis-swift/-sitepoint-點(diǎn)擊數:2

Swift的類(lèi)型系統的設計目的在于簡(jiǎn)化我們的生活,為此它強制用戶(hù)遵守嚴格的代碼規范來(lái)達到這一點(diǎn)。毫無(wú)疑問(wèn)這是一件大好事,它鼓勵程序員們編寫(xiě)更好更正確的代碼。然而,當Swift與歷史遺留的代碼庫、特別是C語(yǔ)言庫進(jìn)行交互時(shí),問(wèn)題出現了。我們需要面對的現實(shí)是許多C語(yǔ)言庫濫用類(lèi)型,以至于它們對Swift的編譯器并不友好。蘋(píng)果的Swift團隊的確花了不少功夫來(lái)支持C的一些基礎特性,比如C字符串。但當在Swift中使用歷史遺留的C語(yǔ)言庫時(shí),我們還是會(huì )面臨一些問(wèn)題。下面我們就來(lái)解決這些問(wèn)題。

在開(kāi)始之前我必須先提醒一下,這篇文章代碼里的許多操作有潛在的安全問(wèn)題,即使它們繞過(guò)了Swift編譯器的類(lèi)型系統的檢查,我建議你仔細的閱讀并且不要復制粘貼文章內的代碼。它們不是Stack Overflow,不恰當的使用它們會(huì )真的導致記憶體損壞、內存泄露,或者至少讓你的程序崩潰。

基礎概念

大多數時(shí)候,C語(yǔ)言指針有兩種方法導入到Swift中:

UnsafePointerUnsafeMutablePointer

這里的T是C類(lèi)型的等價(jià)的Swift類(lèi)型。聲明為常量的指針被導入為UnsafePointer,非常量的指針則被導入為UnsafeMutablePoinger。

這里有一些示例:

C:void myFunction(const int *myConstIntPointer);Swift:func myFunction(myConstIntPointer: UnsafePointer)C:void myOtherFunction(unsigned int *myUnsignedIntPointer);Swift:func myOtherFunction(myUnsignedIntPointer: UnsafeMutablePointer)C:void iTakeAVoidPointer(void *aVoidPointer);Swift:func iTakeAVoidPointer(aVoidPointer: UnsafeMutablePointer)

如果不知道指針的類(lèi)型,比如一個(gè)為前置聲明的指針,則使用COpaquePointer。

C:struct SomeThing;void iTakeAnOpaquePointer(struct SomeThing *someThing);Swift:func iTakeAnOpaquePointer(someThing: COpaquePointer)

傳遞指針到Swift對象

在很多情況下,傳遞指針到Swift對象和使用inout運算符一樣簡(jiǎn)單,后者類(lèi)似于C語(yǔ)言中的and運算符。

Swift:let myInt: = 42myFunction(&myInt)var myUnsignedInt: UInt = 7myOtherFunction(&myUnsignedInt)

這里有兩個(gè)非常重要但容易被忽視的細節。

1. 當使用inout運算符時(shí),使用var聲明的變量和使用let聲明的常量被分別轉換到UnsafePointer和UnsafeMutablePoinger,如果你不注意原來(lái)代碼中的類(lèi)型,就很容易出錯。你可以試著(zhù)向本來(lái)是UnsafeMutablePoinger的地方傳遞一個(gè)UnsafePointer看看,編譯器會(huì )報錯。

2. 這個(gè)運算符只在將Swift值和引用作為函數參數傳遞的上下文時(shí)生效,且該函數參數只接受UnsafePointer和UnsafeMutablePoinger兩種類(lèi)型。你不能在其它上下文獲得這些指針。比如,下面的代碼是無(wú)效的,并且會(huì )返回編譯錯誤。

Swift:let x = 42let y = &x

你可能會(huì )不時(shí)的需要交互操作一個(gè)API。來(lái)獲取或返回一個(gè)空指針以代替顯式類(lèi)型,不幸的是這種做法在C語(yǔ)言里很普遍,導致無(wú)法指定一個(gè)通用類(lèi)型。

C:void takesAnObject(void *theObject);

如果你確定函數需要獲取什么類(lèi)型的參數,你可以使用withUnsafePointer和unsafeBitCast將對象強制轉換為空指針。比如,假設takesAnObject需要獲取指向int的指針。

var test = 42withUnsafePointer(&test, { (ptr: UnsafePointer) -> Void in    var voidPtr: UnsafePointer = unsafeBitCast(ptr, UnsafePointer.self)    takesAnObject(voidPtr)})

為了轉換它,首先我們需要調用withUnsafeMutablePointer,這個(gè)通用函數包含兩個(gè)參數。

第一個(gè)參數是T類(lèi)型的inout運算符,第二個(gè)是(UnsafePointer) -> ResultType的閉包。函數通過(guò)指向第一個(gè)參數的指針來(lái)調用閉包,然后然后將其作為閉包唯一的參數傳遞,最后函數返回閉包的結果。在上面的例子里,閉包的類(lèi)型被設置為Void,因此將不返回值。返回值的例子如下:

let ret = withUnsafePointer(&test, { (ptr: UnsafePointer) -> Int32 in    var voidPtr: UnsafePointer = unsafeBitCast(ptr, UnsafePointer.self)    return takesAnObjectAndReturnsAnInt(voidPtr)})println(ret)

注意:你需要自己修改指針,通過(guò)withUnsafeMutablePointer變體來(lái)完成修改。

為方便起見(jiàn),Swift也包括傳遞兩個(gè)指針的變體:

var x: Int = 7var y: Double = 4withUnsafePointers(&x, &y, { (ptr1: UnsafePointer, ptr2: UnsafePointer) -> Void in    var voidPtr1: UnsafePointer = unsafeBitCast(ptr1, UnsafePointer.self)    var voidPtr2: UnsafePointer = unsafeBitCast(ptr2, UnsafePointer.self)    takesTwoPointers(voidPtr1, voidPtr2)})

關(guān)于unsafeBitCast

unsafeBitCast是一個(gè)極度危險的操作。文檔將其描述為“將某物強制轉換為和其他東西相同的比特位”。在上面我們能夠安全的使用它的原因是,我們只是簡(jiǎn)單的轉換不同類(lèi)型的指針,并且這些指針的比特位都是相同的。這也是我們?yōu)槭裁幢仨毾日{用withUnsafePointer來(lái)獲取UnsafePointer,然后將其轉換為UnsafePointer的原因。

在一開(kāi)始這可能會(huì )造成迷惑,特別是當處理與指針相同的類(lèi)型時(shí),比如Swift里的Int(在目前所有可用的平臺,一個(gè)指針的長(cháng)度是一個(gè)字符,Int的長(cháng)度同樣也是一個(gè)字符)。

比如你很容易就會(huì )犯下面的錯誤:

var x: Int = 7let xPtr = unsafeBitCast(x, UnsafePointer.self)

這段代碼的意圖是獲取一個(gè)指針并傳遞給x。它會(huì )給人造成誤解,盡管編譯能通過(guò)并且能運行,但會(huì )導致一個(gè)意外錯誤。這是因為C API沒(méi)有獲取指針并傳遞給x,而是接收位于0x7或者其他地方的指針。

因為unsafeBitCast要求類(lèi)型的長(cháng)度相等,所以當試圖轉換Int8或者一個(gè)字節的整型時(shí)沒(méi)那么陰險了。

var x: Int8 = 7let xPtr = unsafeBitCast(x, UnsafePointer.self)

這段代碼會(huì )簡(jiǎn)單的導致unsafeBitCast拋出異常和程序崩潰。

與C語(yǔ)言中的結構體交互

讓我們用實(shí)際的示例來(lái)展示這一部分。如果你想檢索計算機所運行的系統信息,有一個(gè)C API:uname(2)可以達到目的。它接收指針指到一個(gè)數據結構,并且用系統信息填充所提供的對象,如OS名稱(chēng)和版本或者硬件識別符。但這里有一個(gè)問(wèn)題,導入到Swift的結構體是這樣:

struct utsname {    var sysname: (Int8, Int8, ...253 times..., Int8)    var nodename: (Int8, Int8, ...253 times..., Int8)    var release: (Int8, Int8, ...253 times..., Int8)    var version: (Int8, Int8, ...253 times..., Int8)    var machine: (Int8, Int8, ...253 times..., Int8)}

Swift將C中的數組字面量作為元組導入,并且默認的初始化程序要求每個(gè)字段都有值,所以如果你用Swift通常的做法來(lái)做的話(huà),它將會(huì )變成:

var name = utsname(sysname: (0, 0, 0, ..., 0), nodename: (0, 0, 0, ..., 0), etc)utsname(&name)var machine = name.machineprintln(machine)

這不是一個(gè)好方法。并且還存在另一個(gè)問(wèn)題。因為utsname里的machine字段是元組,所以當使用println時(shí)將輸出256位的Int8,但實(shí)際上只有字符串開(kāi)始的幾個(gè)ASCII值是我們需要的。

那么,如何解決這個(gè)問(wèn)題?

Swift里的UnsafeMutablePointer提供兩個(gè)方法,alloc(Int)和dealloc(Int),分別用來(lái)分配和解除分配模板T的數量參數。我們可以用這些API來(lái)簡(jiǎn)化我們的代碼:

let name = UnsafeMutablePointer.alloc(1)uname(name)let machine = withUnsafePointer(&name.memory.machine, { (ptr) -> String? inlet int8Ptr = unsafeBitCast(ptr, UnsafePointer.self)return String.fromCString(int8Ptr)})name.dealloc(1)if let m = machine {println(m)}

第一步是調用withUnsafePointer,將機器的元組傳遞給它,并通知它我們的閉包將返回一個(gè)附加字符串。

在閉包里面我們將指針轉換為UnsafePointer,即該值的最等價(jià)的表述。除此之外,Swift的String包含一個(gè)類(lèi)方法來(lái)初始化UnsafePointer,這里的CChar是Int8類(lèi)型的別名(typealias),所以我們能夠將我們的新指針傳遞給初始化程序并且返回所需要的信息。

在獲取withUnsafePointer的結果之后,我們能夠測試它是否是let的條件聲明,并打印出結果。對這個(gè)例子來(lái)說(shuō),它輸出了期望的字段“x86_64”。

總結

最后,說(shuō)一下免責聲明。在Swift中使用不安全的API應該被視為最后手段,因為它們是潛在不安全的。當我們轉換遺留的C和Objective-C代碼到Swift中,有很大可能性我們會(huì )繼續需要這些API來(lái)兼容現有工具。然而,當使用withUnsafePointer和unsafeBitCast作為首選手段時(shí)應該始終抱有懷疑態(tài)度,并尋找其他更好的解決方案。

新的代碼應該盡可能符合語(yǔ)言習慣,不要在Swift代碼中使用不安全的API。作為軟件開(kāi)發(fā)者,你應該了解如何使用你的工具以及什么地方該使用和什么地方不該使用。Swift將現代化帶給了OS X和iOS開(kāi)發(fā),我們必須尊重它的理念。

  •  
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
iOS中堆和棧的使用
C++基礎知識易錯點(diǎn)總結
[18] const正確性, C++ FAQ Lite
C++11新標準
C++語(yǔ)言學(xué)習筆記(一)
C++ Primer:類(lèi)設計者的工具
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久