Как создать экземпляр Swift типа UnsafePointer<UnsafePointer?>! для перехода к функции C

#c #swift #unsafe-pointers

#c #swift #небезопасные указатели

Вопрос:

Я пытаюсь вызвать функцию C из Swift

Один из аргументов функции C определяется как тип:

const char * const * i_argv

В Xcode автоматическое завершение сопоставляет это типу Swift:

_ i_argv: UnsafePointer<UnsafePointer<Int8>?>!

Все мои попытки создать экземпляр этого типа завершились неудачей

Я хочу передать массив из двух Int8

let args: [Int8] = [ 1, 1 ]

Если я передаю это напрямую, я получаю сообщение об ошибке:

cannot convert value of type 'UnsafePointer<Int8>' to expected argument type 'UnsafePointer<UnsafePointer<Int8>?>'

Затем я попытался обернуть массив во внешний UnsafePointer

let argsp: UnsafePointer<Optional<UnsafePointer<Int8>>> = UnsafePointer(args)

Но, похоже, это работает не так, как ожидалось, и выдает ошибку:

cannot assign value of type 'UnsafePointer<Int8>' to type 'UnsafePointer<Optional<UnsafePointer<Int8>>>'

Я не могу понять, как обернуть тип UnsafePointer массива внешним UnsafePointer

Редактировать:

Пример из проекта C:

     #define FIB_ARG_VALUE  "40"
    const char* i_argv[2] = { FIB_ARG_VALUE, NULL };
    result = m3_CallWithArgs (f, 1, i_argv);
  

После вашего комментария мне удалось скомпилировать код Swift со следующей конструкцией аргумента (просто тест компиляции)

let argsp: [UnsafePointer<Int8>?] = [ UnsafePointer([1,2,3]), UnsafePointer("40".cString(using: String.Encoding.utf8)) ]

Это все еще выдает предупреждение о создании висячих указателей

Комментарии:

1. Когда тип аргумента UnsafePointer<UnsafePointer<Int8>?>! , вам нужно передать массив UnsafePointer<Int8>? . Итак, передавать массив из двух Int8 не имеет смысла. Можете ли вы показать пример использования функции в C?

2. Обновлено исходное сообщение

3. Спасибо за обновление, можете ли вы показать, как FIB_ARG_VALUE определяется?

4. Добавлено определение FIB_ARG_VALUE и компиляционная (с предупреждениями) версия аргументов.

Ответ №1:

Как я написал в своем комментарии,

Когда тип аргумента UnsafePointer<UnsafePointer<Int8>?>! , вам нужно передать массив UnsafePointer<Int8>? .

В вашей обновленной части вы понимаете часть, которая передает массив UnsafePointer<Int8>? , но вам не удалось создать каждый элемент массива.

Эквивалент Swift вашему примеру из проекта C будет:

 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)
}
  

Правильный способ для вашего кода теста компиляции должен выглядеть следующим образом:

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

В обоих случаях я предполагаю, что ваши функции C не будут сохранять указатели, переданные в i_argv для использования в будущем, в противном случае вам потребуется некоторая модификация, чтобы скопировать содержимое на некоторый стабильный адрес.

Или вам может потребоваться изменить некоторые другие части в зависимости от фактических аргументов или функциональности функции C.