Reputation: 3
I am trying to call a C function from Swift
One of the arguments to the C function is defined as the type:
const char * const * i_argv
In Xcode auto completion maps this to Swift type:
_ i_argv: UnsafePointer<UnsafePointer<Int8>?>!
All my attempts to create an instance of this type have failed
I want to pass an array of two Int8
let args: [Int8] = [ 1, 1 ]
If I pass this directly I get the error:
cannot convert value of type 'UnsafePointer<Int8>' to expected argument type 'UnsafePointer<UnsafePointer<Int8>?>'
So I then tried to wrap the array in an outer UnsafePointer
let argsp: UnsafePointer<Optional<UnsafePointer<Int8>>> = UnsafePointer(args)
But this does not appear to work as expected and gives the error:
cannot assign value of type 'UnsafePointer<Int8>' to type 'UnsafePointer<Optional<UnsafePointer<Int8>>>'
I can't figure out how to wrap the UnsafePointer type of the array with an outer UnsafePointer
Edit:
An example from the C project:
#define FIB_ARG_VALUE "40"
const char* i_argv[2] = { FIB_ARG_VALUE, NULL };
result = m3_CallWithArgs (f, 1, i_argv);
Following your comment I have managed to get the Swift code to compile with the following argument construction (just a compilation test)
let argsp: [UnsafePointer<Int8>?] = [ UnsafePointer([1,2,3]), UnsafePointer("40".cString(using: String.Encoding.utf8)) ]
This still gives a warning about creating dangling pointers
Upvotes: 0
Views: 217
Reputation: 47876
As I wrote in my comment,
When the argument type is
UnsafePointer<UnsafePointer<Int8>?>!
, you need to pass an Array ofUnsafePointer<Int8>?
.
In your re-updated part, you understand the part to pass an Array of UnsafePointer<Int8>?
, but you have failed to create each element of the Array.
The Swift equivalent to your example from the C project would be:
let FIB_ARG_VALUE = "40"
let result: CInt = FIB_ARG_VALUE.withCString {pointer in
let i_argv: [UnsafePointer<Int8>?] = [
pointer,
nil
]
return m3_CallWithArgs(f, 1, i_argv)
}
The right way for your compilation test code should look like:
let arg1: [Int8] = [1,2,3]
let arg2: String = "40"
_ = arg1.withUnsafeBufferPointer {arg1BufPtr in
arg2.withCString {arg2Ptr in
let argsp: [UnsafePointer<Int8>?] = [ arg1BufPtr.baseAddress,
arg2Ptr
]
//Use `argsp` inside this block.
//...
}
}
In both cases, I assume your C functions would not keep the pointers passed in i_argv
for future use, otherwise you need some modification to copy the content to some stable address.
Or you many need to modify some other parts depending on the actual arguments or the functionality of the C function.
Upvotes: 1