#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.