Присвойте массив строк Swift структурной переменной C, приняв значение char ** - PullRequest
0 голосов
/ 31 мая 2018

Я пытаюсь взаимодействовать со старым приложением / библиотекой терминала C от Swift.Я успешно интегрировал исходный код и соединил заголовки от C до Swift.Код компилируется и запускается, я могу получить доступ ко всем функциям из C-библиотеки в swift.

В C-библиотеке есть структура, которую мне нужно инициализировать [Функция уже существует, которая принимает указатель] и присваивать значения структурепеременные [Вручную].

C-структура:

Struct args{
char ** var1;
unsigned char * var2;
char * var3;
}

и вызов функции инициализации:

init(args * ptr);

Как вызвать функцию внутри swift и присвоить значения var1и var2?

1. Будет ли следующий фрагмент успешно инициализировать структуру?

let Ptr = UnsafeMutablePointer<args>.allocate(capacity: 1)
var args = args()
Ptr.pointee = args
init(Ptr)

2. Как назначить значения для var1, var2 и var3, если мы успешно инициализируем?

Они отображаются как:

var1: UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>!
var2: UnsafeMutablePointer<Uint8>!
var3: UnsafeMutablePointer<Int8>!    

Например, var1 = {"a", "b"} , var2 = {1,2,3} и var3 = "a"

Я проверил следующие ссылки и не работал:

Как передать массив строк Swift в функцию Cпринимая параметр char ** : дает 'inout [UnsafeMutablePointer?] набрать UnsafeMutablePointer?>!'ошибка

Преобразование массива Swift из String в a в указатель массива строки C : дает 'inout [UnsafeMutablePointer?] для ввода UnsafeMutablePointer?>!'ошибка

Нет встроенной поддержки массивов строк C : для этого требуется больше усилий и в надежде получить более простую версию

github - Обертки Swift для Cфункции, принимающие char ** аргументы : выдает 'inout [UnsafeMutablePointer] для ввода UnsafeMutablePointer?>!'Ошибка

1 Ответ

0 голосов
/ 31 мая 2018

Это довольно широкий вопрос, поэтому вот несколько ссылок и наблюдений с несколькими примерами.Надеемся, что они полезны.

Пожалуйста, смотрите документацию Apple для UnsafeMutablePointer struct, а также 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, потому что он зарезервирован для инициализации именных классов.Давайте назовем переменную 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.

...