我看到一些行爲斯威夫特和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。