将 Swift 字符串数组分配给采用 char ** 值的 C 结构变量
Assign an array of Swift strings to a C structure variable taking a char ** value
我正在尝试与来自 Swift 的旧 C 终端 app/library 进行交互。我已经成功地集成了源代码并将 headers 从 C 桥接到 Swift。代码编译并运行,我可以访问 C 库中的所有函数到 swift.
C 库中有一个结构,我需要对其进行初始化[函数已经存在,它采用指针] 并[手动] 为结构变量赋值。
C-structure:
Struct args{
char ** var1;
unsigned char * var2;
char * var3;
}
和初始化函数调用:
init(args * ptr);
如何调用swift里面的函数并给var1和var2赋值?
1.Will 以下片段是否成功初始化结构?
let Ptr = UnsafeMutablePointer<args>.allocate(capacity: 1)
var args = args()
Ptr.pointee = args
init(Ptr)
2.How 假设我们成功初始化,给 var1、var2 和 var3 赋值?
它们映射为:
var1: UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>!
var2: UnsafeMutablePointer<Uint8>!
var3: UnsafeMutablePointer<Int8>!
例如
var1 = {"a", "b"}, var2 = {1,2,3} 和 var3 = "a"
我测试了以下链接但没有用:
如何将 Swift 字符串数组传递给采用 char ** 参数的 C 函数
:给出 'inout[UnsafeMutablePointer?] to type UnsafeMutablePointer?>!' 错误
将一个Swift字符串数组转换为一个C字符串数组指针
:给出 'inout[UnsafeMutablePointer?] to type UnsafeMutablePointer?>!' 错误
No built-in support for arrays of C strings : 这个需要更多的努力,希望得到更简单的版本
github - Swift 采用 char** 参数的 C 函数包装器
:给出 'inout[UnsafeMutablePointer] to type UnsafeMutablePointer?>!' 错误
这是一个相当广泛的问题,所以这里有一些参考和观察以及一些例子。希望这些对您有所帮助。
请参阅 Apple 的 UnsafeMutablePointer
结构文档以及 String
和 NSString
:
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
在这个回答中,我也遗漏了很多内存管理方面以及诸如跟踪 var1
和 var2
数组大小的事情,因为我不了解您图书馆的具体情况。
关于初始化结构的片段,你不能使用类型名作为变量名,init
会混淆 Swift 编译器,因为它是为命名保留的 class初始值设定项。让我们将变量命名为 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 编码。
我正在尝试与来自 Swift 的旧 C 终端 app/library 进行交互。我已经成功地集成了源代码并将 headers 从 C 桥接到 Swift。代码编译并运行,我可以访问 C 库中的所有函数到 swift.
C 库中有一个结构,我需要对其进行初始化[函数已经存在,它采用指针] 并[手动] 为结构变量赋值。
C-structure:
Struct args{
char ** var1;
unsigned char * var2;
char * var3;
}
和初始化函数调用:
init(args * ptr);
如何调用swift里面的函数并给var1和var2赋值?
1.Will 以下片段是否成功初始化结构?
let Ptr = UnsafeMutablePointer<args>.allocate(capacity: 1)
var args = args()
Ptr.pointee = args
init(Ptr)
2.How 假设我们成功初始化,给 var1、var2 和 var3 赋值?
它们映射为:
var1: UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>!
var2: UnsafeMutablePointer<Uint8>!
var3: UnsafeMutablePointer<Int8>!
例如 var1 = {"a", "b"}, var2 = {1,2,3} 和 var3 = "a"
我测试了以下链接但没有用:
如何将 Swift 字符串数组传递给采用 char ** 参数的 C 函数 :给出 'inout[UnsafeMutablePointer?] to type UnsafeMutablePointer?>!' 错误
将一个Swift字符串数组转换为一个C字符串数组指针 :给出 'inout[UnsafeMutablePointer?] to type UnsafeMutablePointer?>!' 错误
No built-in support for arrays of C strings : 这个需要更多的努力,希望得到更简单的版本
github - Swift 采用 char** 参数的 C 函数包装器 :给出 'inout[UnsafeMutablePointer] to type UnsafeMutablePointer?>!' 错误
这是一个相当广泛的问题,所以这里有一些参考和观察以及一些例子。希望这些对您有所帮助。
请参阅 Apple 的 UnsafeMutablePointer
结构文档以及 String
和 NSString
:
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
在这个回答中,我也遗漏了很多内存管理方面以及诸如跟踪 var1
和 var2
数组大小的事情,因为我不了解您图书馆的具体情况。
关于初始化结构的片段,你不能使用类型名作为变量名,init
会混淆 Swift 编译器,因为它是为命名保留的 class初始值设定项。让我们将变量命名为 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 编码。