2016-10-18 166 views
0

我看到一些行爲斯威夫特和C之間傳遞字符串時,我不明白,請看下面的斯威夫特功能:從斯威夫特字符串傳遞到C回斯威夫特

func demo() 
{ 
    print("\n\n\n\n")               // Line A 

    let str = "thisisastring" 
    let strptr = UnsafePointer<Int8>(str)   
    let strptr_cstring = String(cString: strptr) 
    print("from swift: str = '\(str)'") 
    print("from swift: strptr = \(strptr)") 
    print("from swift: strptr.pointee = \(strptr.pointee)") 
    print("from swift: strptr_cstring = '\(strptr_cstring)'") 
    print("from swift: String(cString: strptr) = '\(String(cString: strptr))'") 

    let ret_strptr = return_string(str)!          // Line B1 
    //let ret_strptr = return_string(strptr)!         // Line B2 
    //let ret_strptr = strptr             // Line B3 

    print("from swift: ret_strptr = \(ret_strptr) ") 
    print("from swift: ret_strptr.pointee = \(ret_strptr.pointee)") 
    let ret_strptr_cstring = String(cString: ret_strptr) 
    print("from swift: ret_strptr_cstring = '\(ret_strptr_cstring)'") 
    print("from swift: String(cString: ret_strptr) = '\(String(cString: ret_strptr))'") 
} 

而C函數:

const char *return_string(const char *c) 
{ 
    printf("from c: got pointer %p = %s\n",c,c); 
    return c; 
} 

如果我運行demo,因爲它是上述(所以只有線B2和B3被註釋掉),I得到以下輸出:

from swift: str = 'thisisastring' 
from swift: strptr = 0x000000010021b8a0 
from swift: strptr.pointee = 116 
from swift: strptr_cstring = 'thisisastring' 
from swift: String(cString: strptr) = 'thisisastring' 
from c: got pointer 0x10021b9b0 = thisisastring 
from swift: ret_strptr = 0x000000010021b9b0 
from swift: ret_strptr.pointee = 102 
from swift: ret_strptr_cstring = '102m swift: ret_' 
from swift: String(cString: ret_strptr) = 'P�!' 

有兩件事讓我感到驚訝:1)C代碼獲取指針0x10021b9b0,而在Swift中,該字符串被存儲在0x000000010021b8a0處。我會期望他們是相同的,但我猜Swift在將字符串傳遞給C之前創建了一個字符串的副本? 2)更令人驚訝的是雖然從C返回Swift的指針是相同的位置,但內容是不同的;此外,最後兩個打印語句產生不同的輸出。

現在,如果我只是在demo註釋掉線A,我得到如下結果:

from swift: str = 'thisisastring' 
from swift: strptr = 0x00000001003894b0 
from swift: strptr.pointee = 0 
from swift: strptr_cstring = 'S\212' 
from swift: String(cString: strptr) = '' 
from c: got pointer 0x100469640 = thisisastring 
from swift: ret_strptr = 0x0000000100469640 
from swift: ret_strptr.pointee = 48 
from swift: ret_strptr_cstring = '48000010046964' 
from swift: String(cString: ret_strptr) = '48000010046964' 

這是令人驚訝,因爲在調用C函數之前,所有的東西是不正確。

如果我然後註釋掉線B1並取消B3(只刪除調用C),我得到預期的輸出:

from swift: str = 'thisisastring' 
from swift: strptr = 0x00000001004809b0 
from swift: strptr.pointee = 116 
from swift: strptr_cstring = 'thisisastring' 
from swift: String(cString: strptr) = 'thisisastring' 
from swift: ret_strptr = 0x00000001004809b0 
from swift: ret_strptr.pointee = 116 
from swift: ret_strptr_cstring = 'thisisastring' 
from swift: String(cString: ret_strptr) = 'thisisastring' 

如果我用線B2註釋掉運行(註釋掉A,B1和B3),我得到:

from swift: str = 'thisisastring' 
from swift: strptr = 0x0000000100203550 
from swift: strptr.pointee = 0 
from swift: strptr_cstring = '2' 
from swift: String(cString: strptr) = '' 
from c: got pointer 0x100203550 = 
from swift: ret_strptr = 0x0000000100203550 
from swift: ret_strptr.pointee = 0 
from swift: ret_strptr_cstring = '' 
from swift: String(cString: ret_strptr) = '' 

最後,如果我用線A和B2註釋掉(B1和B3註釋掉),我得到預期的結果跑:

from swift: str = 'thisisastring' 
from swift: strptr = 0x00000001005533d0 
from swift: strptr.pointee = 116 
from swift: strptr_cstring = 'thisisastring' 
from swift: String(cString: strptr) = 'thisisastring' 
from c: got pointer 0x1005533d0 = thisisastring 
from swift: ret_strptr = 0x00000001005533d0 
from swift: ret_strptr.pointee = 116 
from swift: ret_strptr_cstring = 'thisisastring' 
from swift: String(cString: ret_strptr) = 'thisisastring' 

在我看來,像C這樣的呼叫以不可預知的方式跺腳記憶,但是我在這裏做了些什麼不正確的事嗎?

在macOS Sierra上運行,Xcode 8.0,Swift 3.0。

回答