简体   繁体   English

将Swift字符串数组分配给具有char **值的C结构变量

[英]Assign an array of Swift strings to a C structure variable taking a char ** value

I'm trying to interact with an old C terminal app/library from Swift. 我正在尝试与Swift的旧C终端应用程序/库进行交互。 I've successfully integrated the source code and bridged the headers from C to Swift. 我已经成功集成了源代码,并将标头从C桥接到Swift。 The code compiles and runs, I can access all functions from C - library into swift. 代码编译并运行后,我可以从C-库快速访问所有功能。

There is a structure in C - library which I need to initialize[Function already exists which takes pointer] and assign values to structure variables[Manually]. C库中有一个结构,我需要初始化[函数已经存在,它需要指针],然后将值分配给结构变量[手动]。

C-structure: C-结构:

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

and Initialization function call: 和初始化函数调用:

init(args * ptr);

How to call the function inside swift and assign values to var1 and var2? 如何在swift内部调用函数并将值分配给var1和var2?

1.Will following snippet successfully initialize the structure? 1.以下代码段会成功初始化结构吗?

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

2.How to assign values to var1, var2 & var3 assuming we successfully initialize? 2.假设我们成功初始化,如何给var1,var2和var3赋值?

They are mapped as: 它们被映射为:

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

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

I've tested following links and did not work: 我已经测试了以下链接,但无法正常工作:

How to pass an array of Swift strings to a C function taking a char ** parameter : gives 'inout[UnsafeMutablePointer?] to type UnsafeMutablePointer?>!' 如何通过使用char **参数将Swift字符串数组传递给C函数 :给出'inout [UnsafeMutablePointer?]键入UnsafeMutablePointer?>!“ error 错误

Convert a Swift Array of String to a to a C string array pointer : gives 'inout[UnsafeMutablePointer?] to type UnsafeMutablePointer?>!' 将字符串的Swift数组转换为C字符串数组指针 :给出“ inout [UnsafeMutablePointer?]键入UnsafeMutablePointer?>!” error 错误

No built-in support for arrays of C strings : this one needs more efforts and hoping to get easier version 没有内置的C字符串数组支持 :这需要更多的努力,并希望获得更简单的版本

github - Swift wrappers for C functions taking char** arguments : gives 'inout[UnsafeMutablePointer] to type UnsafeMutablePointer?>!' github-用于带有char **参数的C函数的Swift包装器 :给出'inout [UnsafeMutablePointer]键入UnsafeMutablePointer?>!“ error 错误

This is quite a broad question, so here are some references and observations with a few examples. 这是一个相当广泛的问题,因此这里是一些参考和观察以及一些示例。 Hopefully these are helpful. 希望这些对您有所帮助。

Please see Apple's documentation for UnsafeMutablePointer struct and also String and NSString : 请参阅Apple的UnsafeMutablePointer结构以及StringNSString文档:

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

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

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

Another useful reading is Apple's docs about C and Swift interop: https://developer.apple.com/documentation/swift/imported_c_and_objective_c_apis 另一个有用的读物​​是苹果公司有关C和Swift互操作的文档: https : //developer.apple.com/documentation/swift/imported_c_and_objective_c_apis

In this answer I'm also leaving out a lot of memory management aspects as well as things such as keeping track of the size of var1 and var2 arrays, since I don't know the specifics of your library. 在此答案中,由于我不了解您的库的详细信息,因此我还忽略了很多内存管理方面的内容,例如跟踪var1var2数组的大小。

Regarding the snippet for initializing the structure, you can't use the type name as the variable name and init will confuse the Swift compiler because it's reserved for naming class initializers. 关于用于初始化结构的代码段,您不能使用类型名称作为变量名称,并且init会使Swift编译器感到困惑,因为它是为命名类初始化程序保留的。 Let's name the variable myArgs instead of args and assume the C library initialization function is named initialize ; 让我们将变量myArgs命名为args并假设C库初始化函数的名称为initialize if it's indeed init , one can easily write a wrapper named differently. 如果确实是init ,则可以轻松编写一个不同名称的包装器。 Another problem with the snippet is that myArgs will remain unchanged after initialization, Ptr will actually get initialized, so you would have to use Ptr to access the initialized args structure. 该代码段的另一个问题是myArgs在初始化后将保持不变,而Ptr实际上会被初始化,因此您必须使用Ptr来访问已初始化的args结构。 Thus we can omit Ptr and use implicit bridging to pass myArgs to the initialization function. 因此,我们可以省略Ptr并使用隐式桥接将myArgs传递给初始化函数。 The snippet becomes 片段变成

var myArgs = args()
initialize(&myArgs)

Now you can access the members as follows: 现在,您可以按以下方式访问成员:

// 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

Now let's set var1 to be {"aa", "bbb"} : 现在,将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...")}

Here is an example of setting var2 to be an array of 5 elements equal to 200: 这是将var2设置为5个元素等于200的数组的示例:

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

And setting the value of var3: 并设置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...") }

The above examples assume UTF8 encoding. 上面的示例假定使用UTF8编码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM