2015-07-19 2 views
1

Я пытаюсь вернуть массив структур из кода C++ в быстрый код.Пропустить массив структур из C++ в swift

Swift код:

struct CPoint { 
    let x: CDouble 
    let y: CDouble 
} 

struct CStruct { 
    let p1: CPoint 
    let d: CDouble 
    let p2: CPoint 
    let i: CInt 
} 

func get_structs() { 

    let cnt = ... //Getting size from c++ code 
    var buf = [CStruct](count: cnt, repeatedValue: CStruct(p1: CPoint(x: 0, y: 0), d: 0, p2: CPoint(x: 0, y: 0), i: 0)) 
    let addr = UnsafeMutableBufferPointer(start: &buf, count: buf.count).baseAddress 
    get_structs_c(addr) 

    for cstruct in buf { 
     //First cstruct is OK. Next are corrupted. 
    } 
} 

C++ код:

typedef struct Point { 
    double x; 
    double y; 
} 

typedef struct Struct { 
    Point p1; 
    double d; 
    Point p2; 
    int i; 
} 

void get_structs_c(void *buf) { 
    Struct * structs = (Struct *) buf; 
    const std::vector<const Struct *> vec = ... // getting values no matter from where 
    for (int i = 0; i < vec.size(); i++) { 
     const Struct * s = vec.at(i); 
     structs[i] = Struct{ s->p1, s->d, s->p2, s->i}; 
    } 
} 

код прост, однако в итоге поврежденные значения сохраняются в buf.

НО, если я удалить i поле из CStruct и Struct, то он будет возвращать правильные значения, или если я изменить тип i из CInt и int к CDouble и Double, то также будет возвращать правильные значения. Итак, возможно, некоторые проблемы с мостом int.

Я проверил размер CStruct и Struct и оказался таким же 44 байтами.

Любая помощь приветствуется, спасибо заранее!

UPD 1: Он работает правильно, только если размер структуры пропорционален 8 байтам.

UPD 2: Я проверил адресацию памяти и выяснил, что Свифт sizeof говорит, что

struct CStruct { 
    let p1: CPoint 
    let d: CDouble 
    let p2: CPoint 
    let i: CInt 
} 

имеет размер байт, НО & структуры [1] - & структура [0] = !

Если структура перезаказа поля худшей образом:

struct CStruct { 
    let i: CInt 
    let p1: CPoint 
    let d: CDouble 
    let p2: CPoint 
} 

Затем он автоматически выравнивает, sizeof дает размер 48 и он работает правильно.

Является ли такая стандартная несовместимость нормальна?

ответ

1

Ваша функция get_structs_c по своей сути опасна, потому что вы не передаете размер буфера и, следовательно, это уязвимость переполнения буфера! Что вам действительно нужно, это подпись, как это:

struct StructList { 
    Struct* items; 
    size_t size; 
}; 

StructList* CreateAndTransferOwnershipFromC(); 

Или:

size_t CopyFromC(Struct* output_buffer, size_t buffer_size); 

Что, скорее всего, что здесь происходит, что существует несоответствие размера между C++ и Swift версии, где некоторые из буфера не заполняется, или вы переполняете буфер.

В противном случае вы можете столкнуться с проблемой alignment. Более безопасным (но, возможно, менее эффективным) решением здесь будет сериализация/десериализация ваших данных в двоичной кодированной строке, например, с protocol buffers, которая может более легко гарантировать двоичную совместимость на обоих концах. В противном случае вам, вероятно, понадобится использовать один из GCC compiler directives для выравнивания/упаковки, чтобы убедиться в его правильности.

+0

Благодарим за консультацию, используя это только для тестирования. Но количество структур в swift-массиве такое же, как количество структур в C++-коде, а 'sizeof' дает одинаковый размер структур и как объяснить тот факт, что все работает правильно с удвоением? И не мог бы я получить ошибку переполнения в этом случае? Я просто перепутал ценности. – Tzoiker

+0

Это по-прежнему довольно опасная вещь, которую вы делаете (поэтому я настоятельно рекомендую явно указать размер буфера), но это может быть проблема упаковки/выравнивания ... обновленный ответ. –

+0

ОК, спасибо, проверит. – Tzoiker

Смежные вопросы