我试图将结构数组从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:仅当struct的大小与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,并且可以正常工作。这样的默认不兼容性正常吗?
最佳答案
您的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之一进行对齐/打包以确保其正确。
关于c++ - 从C++传递结构数组到Swift,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31496905/