将字符串从 Swift 传递到 C 返回到 Swift
Passing string from Swift to C back to Swift
在 Swift 和 C 之间传递字符串时,我看到一些我不理解的行为。考虑以下 Swift 函数:
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 被注释掉),我得到以下输出:
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 = 'S2'
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.
如果您想要来自 NSString 的 C 字符串,请使用 cString
or getCString
。
在 Swift 和 C 之间传递字符串时,我看到一些我不理解的行为。考虑以下 Swift 函数:
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 被注释掉),我得到以下输出:
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 = 'S2'
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.
如果您想要来自 NSString 的 C 字符串,请使用 cString
or getCString
。