如何将C++结构体转为兼容C约定的Swift类型?遇内存访问错误求解
问题描述
有一个位于动态库中的C++结构体定义如下:
typedef struct { int a; } addingTemp;
对应的相加函数实现:
void add(addingTemp a, addingTemp b, addingTemp& c) { c.a = a.a + b.a; }
该函数的导出声明为:
DLL_PUBLIC void add( addingTemp a, addingTemp b, addingTemp* c,);
尝试在Swift中调用该函数时,将addingTemp实现为继承NSObject的类:
public class addingTemp: NSObject { public var a : CInt init(a: CInt = 0) { self.a = a } }
调用代码如下:
typealias add = @convention(c) (addingTemp, addingTemp, UnsafeMutablePointer<addingTemp>) -> Void func addLib(a : addingTemp, b: addingTemp, out: inout addingTemp) -> Void{ guard dylib != nil else { errorDylib() return } guard let sym = dlsym(dylib, "add") else { errorDylib() return } let f = unsafeBitCast(sym, to:add.self ) let result : Void = f(a ,b, &out) // closeDylib() return }
运行时出现内存访问错误,推测是类型不匹配导致存储异常,请问如何在Swift中正确创建符合C兼容约定的结构体?
解决方案
问题核心是Swift中用了引用类型的NSObject子类,而C的结构体是值类型,两者内存布局完全不兼容,导致调用C函数时内存访问出错。正确的做法是在Swift中定义一个与C结构体内存布局一致的值类型结构体,不需要继承任何类。
正确的addingTemp Swift定义
public struct addingTemp { public var a: CInt }
Swift的结构体默认使用与C兼容的内存布局(对于这种简单的平凡结构体),成员a的类型CInt对应C中的int,保证了内存结构完全匹配。
调整后的调用代码
只需将类型替换为上述结构体即可,核心逻辑无需修改:
typealias addFn = @convention(c) (addingTemp, addingTemp, UnsafeMutablePointer<addingTemp>) -> Void func addLib(a: addingTemp, b: addingTemp, out: inout addingTemp) { guard let dylib = dylib else { errorDylib() return } guard let sym = dlsym(dylib, "add") else { errorDylib() return } let f = unsafeBitCast(sym, to: addFn.self) f(a, b, &out) }
关键说明
- C的结构体是值类型,内存中直接存储成员数据;Swift的
NSObject子类是引用类型,内存中存储的是对象指针,两者内存布局完全不同,传递给C函数时会导致参数解析错误,触发内存访问异常。 - 对于仅包含基本数据类型的简单结构体,Swift结构体默认遵循与C一致的内存布局规则,无需额外标记。
内容的提问来源于stack exchange,提问作者Ryan Kim
相关产品推荐
相关产品推荐

