将一个Swift字符串数组赋值给一个C结构变量,取一个char **值

时间:2018-05-30 23:20:40

标签: c swift pointers language-interoperability

我正在尝试与Swift中的旧C终端应用/库进行交互。我已成功集成源代码并将标头从C桥接到Swift。代码编译并运行,我可以从C库中访问所有函数到swift。

C库中有一个结构我需要初始化[函数已存在,它接受指针]并为结构变量赋值[手动]。

C-结构:

Struct args{
char ** var1;
unsigned char * var2;
char * var3;
}

和初始化函数调用:

init(args * ptr);

如何调用swift中的函数并将值赋给var1和var2?

1.下面的代码片段会成功初始化结构吗?

let Ptr = UnsafeMutablePointer<args>.allocate(capacity: 1)
var args = args()
Ptr.pointee = args
init(Ptr)

2.如何为var1,var2和amp;分配值? var3假设我们成功初始化了吗?

它们被映射为:

var1: UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>!
var2: UnsafeMutablePointer<Uint8>!
var3: UnsafeMutablePointer<Int8>!    

例如 var1 = {“a”,“b”} var2 = {1,2,3} var3 =“a”

我测试过以下链接但没有用:

How to pass an array of Swift strings to a C function taking a char ** parameter :给'inout [UnsafeMutablePointer?]输入UnsafeMutablePointer?&gt;!'错误

Convert a Swift Array of String to a to a C string array pointer :给'inout [UnsafeMutablePointer?]输入UnsafeMutablePointer?&gt;!'错误

No built-in support for arrays of C strings:这个需要更多的努力,并希望更容易的版本

github - Swift wrappers for C functions taking char** arguments :给'inout [UnsafeMutablePointer]输入UnsafeMutablePointer?&gt;!'错误

1 个答案:

答案 0 :(得分:0)

这是一个相当广泛的问题,所以这里有一些参考和观察以及一些例子。希望这些都有帮助。

请参阅Apple有关UnsafeMutablePointer结构以及StringNSString的文档:

https://developer.apple.com/documentation/swift/unsafemutablepointer

https://developer.apple.com/documentation/swift/string

https://developer.apple.com/documentation/foundation/nsstring

另一个有用的读物​​是Apple关于C和Swift互操作的文档:https://developer.apple.com/documentation/swift/imported_c_and_objective_c_apis

在这个答案中,我也省略了很多内存管理方面以及跟踪var1var2数组的大小等事情,因为我不知道你图书馆的细节。

关于用于初始化结构的代码段,您不能使用类型名称作为变量名称,init会混淆Swift编译器,因为它保留用于命名类初始化程序。让我们将变量命名为myArgs而不是args,并假设C库初始化函数名为initialize;如果它确实是init,那么可以轻松编写一个名称不同的包装器。该代码段的另一个问题是myArgs在初始化后将保持不变,Ptr实际上会被初始化,因此您必须使用Ptr来访问已初始化的args结构。因此,我们可以省略Ptr并使用隐式桥接将myArgs传递给初始化函数。摘录变为

var myArgs = args()
initialize(&myArgs)

现在您可以按如下方式访问成员:

// Assuming var1 is an array of at least 2 C strings.
// See Swift documentation about optionals on how to deal with 
// cases when this assumption breaks down
let s1 = String(cString: myArgs.var1[0]!)  // 1st element of var1
let s2 = String(cString: myArgs.var1[1]!)  // 2nd element of var1
myArgs.var2.pointee                   // 1st element of var2
(myArgs.var2 + 1).pointee             // 2nd element of var2
let s = String(cString: myArgs.var3)  // value of var3

现在让我们将var1设置为{"aa", "bbb"}

            var var1Buffer = 
UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>.allocate(capacity: 2)
            var var1a : NSString = "aa"
            var var1b : NSString = "bbb"
            var var1aBuffer = UnsafeMutablePointer<Int8>.allocate(
        capacity: var1a.length + 1)
            var var1bBuffer = UnsafeMutablePointer<Int8>.allocate(
        capacity: var1b.length + 1)
            if (var1a.getCString(var1aBuffer, maxLength: var1a.length + 1,
    encoding: String.Encoding.utf8.rawValue)
                && var1b.getCString(var1bBuffer, maxLength: var1b.length + 1,
    encoding: String.Encoding.utf8.rawValue)) {
                var1Buffer[0] = var1aBuffer
                var1Buffer[1] = var1bBuffer
                myArgs.var1 = var1Buffer
            } else { print("Encoding failed...")}

以下是将var2设置为5个元素等于200的数组的示例:

var var2Buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: 5);
var2Buffer.initialize(repeating: 200, count: 5)
myArgs.var2 = var2Buffer

设置var3的值:

let newVar3 : NSString = "This is new variable 3"
var var3Buffer = UnsafeMutablePointer<Int8>.allocate(capacity: newVar3.length + 1)
if (newVar3.getCString(var3Buffer, maxLength: newVar3.length + 1, encoding: String.Encoding.utf8.rawValue)) {
    myArgs.var3 = var3Buffer
} else { print("Encoding failed...") }

以上示例假设采用UTF8编码。