将 Swift 字符串数组转换为 const char * const *

Posted

技术标签:

【中文标题】将 Swift 字符串数组转换为 const char * const *【英文标题】:Array of Swift Strings into const char * const * 【发布时间】:2016-04-22 02:31:26 【问题描述】:

我在将 Swift 字符串数组转换为带有签名的 c 函数数组时遇到问题:

PGconn *PQconnectStartParams(const char * const *keywords, const char * const *values, int expand_dbname)

在 Swift 中,const char * const * 显示为:

<UnsafePointer<UnsafePointer<Int8>>

所以我尝试转换名为“options”的字典 [String:String] 的内容,并将其提供给函数,如下所示:

var keys = [[Int8]]()
var values = [[Int8]]()
for (key, value) in options 
    var int8Array = key.cStringUsingEncoding(NSUTF8StringEncoding)!
    keys.append(int8Array)
    int8Array = value.cStringUsingEncoding(NSUTF8StringEncoding)!
            values.append(int8Array)

pgConnection = PQconnectStartParams(UnsafePointer(keys), UnsafePointer(values), 0)

可以编译运行,但是函数不起作用。

任何见解将不胜感激。

【问题讨论】:

好的:你在谈论一个名为PQconnectdbParams()的函数,但你正在调用一个名为PQconnectStartParams()的函数...? 看看const char * const *keywordskeywords 是指向const 的指针,指向const char 的指针(与char const 相同,均表示“常量字符”)。这意味着您不是在寻找单个字符串(“空终止字符数组”),但您可能正在寻找字符串的 array。有点像char **argv。我对 Swift 了解不多,但您必须弄清楚如何将 Swift 字符串转换为 C 空终止字符数组,然后必须找出如何将这些数组转换为 C 数组我认为是字符串。 对不起。笔误。正在查看文档的错误部分。修复了函数签名,你是对的,我不是在寻找一个以空值结尾的数组。我需要和 cstrings 数组。这就是我认为我在代码中生成的内容。 好的,看起来您正在尝试生成它。但是因为我对 Swift 一无所知,所以我只是想确保您尝试做正确的事情。 为什么.cStringUsingEncoding(NSUTF8StringEncoding) 会返回int8array?我很困惑字符串和 int8 的关系如何? 【参考方案1】:

这并不完美,但至少它有效。

let options = ["key1": "value1", "key2": "value2", "key3": "value3", "key4": "value4"]

var keys = [String]()

for (key, value) in options 

    keys.append(key)


//you need to identify how many paramenters should be provided and set them following "static way"
//I did not find how to prepare this dynamically
let cKey1 = keys[0].cStringUsingEncoding(String.defaultCStringEncoding())!
let key1Pointer = UnsafePointer<CChar>(cKey1)

let cKey2 = keys[1].cStringUsingEncoding(String.defaultCStringEncoding())!
let key2Pointer = UnsafePointer<CChar>(cKey2)

let cKey3 = keys[2].cStringUsingEncoding(String.defaultCStringEncoding())!
let key3Pointer = UnsafePointer<CChar>(cKey3)

let cKey4 = keys[3].cStringUsingEncoding(String.defaultCStringEncoding())!
let key4Pointer = UnsafePointer<CChar>(cKey4)


let keysCArray = [key1Pointer, key2Pointer, key3Pointer, key4Pointer]

f(keysCArray)

/*
 C - code

 void f(const char * const *keywords) 

 printf("%s\n", keywords[0]);
 printf("%s\n", keywords[1]);
 printf("%s\n", keywords[2]);
 printf("%s\n", keywords[3]);

 
 */

希望对您有所帮助。如果你愿意,我可以分享我的示例应用程序。

【讨论】:

谢谢梅利法罗。在发布问题之前,我已经尝试过这种方法,但不断收到 EXC_BAD_ACCESS。所以我认为这种方法是错误的。但是您关于确定有多少参数的观点使我意识到数组需要以空值终止。所以我向每个数组添加了一个 UnsafePointer(nil) ,现在一切正常。感谢您打开我的灯泡! 不错的发现!感谢您的反馈。【参考方案2】:

这是 Swift3 中 Array 的一个扩展,它可以通用:

public extension Array 

    // Translate [String] to (const char * const *), which translates to Swift as
    public func cStringArray() throws -> ArrayBridge<Element,CChar> 
        return try ArrayBridge<Element,CChar>(array:self) 
            guard let item = $0 as? String,
                  let translated = item.cString(using: .utf8) else 
                fatalError()
            
            return translated
        
    


/*
 We need to have this intermediate object around to hold on to the translated objects, otherwise they will go away.
 The UnsafePointer won't hold on to the objects that it's pointing to.
 */
public struct ArrayBridge<SwiftType,CType> 

    let originals  :[SwiftType]
    let translated :[[CType]]
    let pointers   :[UnsafePointer<CType>?]
    public let pointer    :UnsafePointer<UnsafePointer<CType>?>

    init(array :[SwiftType], transform: @noescape (SwiftType) throws -> [CType]) throws 
        self.originals = array
        self.translated = try array.map(transform)

        var pointers = [UnsafePointer<CType>?]()
        for item in translated 
            pointers.append(UnsafePointer<CType>(item))
        
        pointers.append(nil)
        self.pointers = pointers
        self.pointer = UnsafePointer(self.pointers)
    

然后你可以通过这样做得到正确的 C 兼容指针

try stringArray.cStringArray().pointer

【讨论】:

以上是关于将 Swift 字符串数组转换为 const char * const *的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Swift 中声明一个静态 const char 数组? [关闭]

error C2664: “int CWnd::GetWindowTextW(LPTSTR,int) const”: 不能将参数 1 从“char [10]”转换为“LP

如何将 Swift 数组转换为字符串?

将 Swift 字符串数组转换为 C 字符串数组指针

将 Swift 字符串数组转换为 C 字符串数组指针

如何将 Int 数组转换为字符串? Swift 中的数组