c - String.withCString 当 String 为 nil 时

标签 c swift interop unsafe-pointers

将要描述的问题与我之前的问题有关: string.withCString and UnsafeMutablePointer(mutating: cstring) wrapped into a function这是我处理 nil 字符串的第一种方法(通过将 withCString 放入函数中) 以及 Mecki 提出的一个问题: Why can't I pass an optional Swift String to C function that allows NULL pointers?

假设有一个 C 函数,如下所示:

unsigned long randomSign(char *pin, char *tag_signature, char *tag_data, char *xyz);

我知道如果我在相应的 swift 函数周围包装 4 个 string.withCString 闭包,该函数将正常工作:

// pin, tag_signature, tag_data and xyz are optional Strings so they may be nil which is a problem for my result.
// corresponding swift function:
// randomSign(pin: UnsafeMutablePointer<Int8>!, tag_signature: UnsafeMutablePointer<Int8>!, tag_data: UnsafeMutablePointer<Int8>!, xyz: UnsafeMutablePointer<Int8>!)
let result = pin.withCString { s1 in return
    tag_signature.withCString {s2 in return
        tag_data.withCString {s3 in return
            xyz.withCString { s4 in return 
                randomSign(UnsafeMutablePointer(mutating: s1), UnsafeMutablePointer(mutating: s2), UnsafeMutablePointer(mutating: s3), UnsafeMutablePointer(mutating: s4))
    }}}}

And so Martin R replied to an easier example ,不需要将闭包包装在 randomSign(arguments) 和 UnsafeMutablePointer(mutating: ...) 周围,因为它也可以获取字符串并进行转换。 但是当我放下闭包并将其用作 Martin R described 时,它在启动 mac 后直接在模拟器上首次启动时工作,但在连续调用 randomSign-Function 时,返回会告诉我,例如 tag_signature 或 pin 将无效(但它实际上是有效的,我不不知道为什么?!)。

这导致我遇到一个问题,我需要 withCString 闭包(目前),但我必须处理 nil-Strings,这将导致应用程序在返回结果时崩溃,因为它无法评估 randomSign -功能。

所以我试着去适应the approach below (also suggested by @Martin R)到 Swift 3,但我没有尝试去适应它。

//Swift-2 written by Martin R
protocol CStringConvertible {
    func withCString<Result>(@noescape f: UnsafePointer<Int8> throws -> Result) rethrows -> Result
}

extension String: CStringConvertible { }

extension Optional where Wrapped: CStringConvertible {
    func withOptionalCString<Result>(@noescape f: UnsafePointer<Int8> -> Result) -> Result {
        if let string = self {
            return string.withCString(f)
        } else {
            return f(nil)
        }
    }
}

//Swift 3: ???

如果有人能告诉我,为什么我的函数只在我使用 withCString 时有效,而在我关闭它时却无效,我将不胜感激 以及是否有人知道如何解决该问题,即将 swift-2 代码正确转换为有效的 swift-3 代码。

最佳答案

问题

let result = randomSign(UnsafeMutablePointer(mutating: pin),
                    UnsafeMutablePointer(mutating: tag_signature),
                    UnsafeMutablePointer(mutating: tag_data),
                    UnsafeMutablePointer(mutating: xyz))

是从 Swift 创建的临时 UTF-8 表示 字符串仅在每次调用 UnsafeMutablePointer() 时有效, 但在调用 randomSign() 期间不一定仍然有效。 (所以我在 https://stackoverflow.com/a/44027397/1187415 中的最后建议 实际上是不正确的,我已经更新了那部分)。

https://stackoverflow.com/a/39363769/1187415 中可能的 Swift 3 包装器版本是

extension Optional where Wrapped == String {
    func withOptionalCString<Result>(_ f: (UnsafeMutablePointer<Int8>?) -> Result) -> Result {
        if let string = self {
            return string.withCString { f(UnsafeMutablePointer(mutating: $0)) }
        } else {
            return f(nil)
        }
    }
}

这处理了可选性转换C字符串指针 到可变指针(根据 randomSign() 的要求)。这可以是 称为

let result = pin.withOptionalCString { s1 in
    tag_signature.withOptionalCString { s2 in
        tag_data.withOptionalCString { s3 in
            xyz.withOptionalCString { s4 in
                randomSign(s1, s2, s3, s4)
            }
        }
    }
}

备注:理论上,将randomSign()的签名改为带const char *参数就可以避免这个问题:

unsigned long randomSign(const char *pin, const char *tag_signature, const char *tag_data, const char *xyz);

哪个可以简单地称为

let result = randomSign(pin, tag_signature, tag_data, xyz)

带有可选或非可选的 Swift 字符串。 但是,这目前不起作用,如中所述 SR-2814 Swift does not correctly pass in multiple optional strings to C function .

关于c - String.withCString 当 String 为 nil 时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44065751/

相关文章:

ios - 将图像从一个 VC 传输到另一个不工作

c# - 打开文件而不(真的)锁定它?

java - Silverlight 与 JBoss WebService 的互操作问题

c++ - 无法使用/OPT :NOREF 在 .NET 中加载 C++ DLL

c - 这个具体示例是否是 C99 中 restrict 关键字的未定义行为?

c - 当用户输入空行时做一些特别的事情

c - 指向字符的指针

将列表的节点与字符串数组进行比较

ios - 将Firebase Admin SDK添加到Swift

ios - Swift:EGODataBaseRowResult 没有名为 Generator 的成员