【问题标题】:Pass array of structs from c++ to swift将结构数组从 c++ 传递给 swift
【发布时间】:2015-07-20 17:45:05
【问题描述】:

我正在尝试将结构数组从 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

但是,如果我从CStructStruct 中删除i 字段,那么它将返回正确的值,或者如果我将i 的类型从CIntint 更改为CDoubleDouble,然后也会返回正确的值。因此,int 桥接可能存在一些问题。

我检查了 CStructStruct 的大小,它似乎是相同的 44 个字节。

任何帮助表示赞赏,在此先感谢!

UPD 1:只有当结构的大小与 8 个字节成正比时才能正常工作。

UPD 2:我检查了内存寻址,发现 swift 的 sizeof 表明了这一点

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

大小为 44 字节,但是 &struct[1] - &struct[0] = 48

如果以更糟糕的方式重新排序结构字段:

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

然后它会自动对齐,sizeof 给出 48 的大小并且它可以正常工作。

这样的默认不兼容正常吗?

【问题讨论】:

    标签: c++ ios swift


    【解决方案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 之一进行对齐/打包以确保其正确。

    【讨论】:

    • 感谢您的建议,仅用于测试。但是 swift 数组中的结构数与 c++ 代码中的结构数相同,sizeof 给出了相同大小的结构,以及如何解释这样一个事实,即一切都与双精度数正常工作?在那种情况下我不会得到溢出错误吗?我只是搞砸了价值观。
    • 这仍然是您正在做的一件非常危险的事情(所以我强烈建议明确传达缓冲区大小),但这可能是一个打包/对齐问题......更新了答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-06
    • 2014-05-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多