novocodev
novocodev

Reputation: 3

How to create instance of Swift type UnsafePointer<UnsafePointer<Int8>?>! to pass to C function

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

Answers (1)

OOPer
OOPer

Reputation: 47876

As I wrote in my comment,

When the argument type is UnsafePointer<UnsafePointer<Int8>?>!, you need to pass an Array of UnsafePointer<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

Related Questions