You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

主机构造体含构造函数时,DLL返回结构体读取垃圾值或触发段错误

问题触发原因
  • 核心原因是C++ 结构体的 ABI 兼容性被自定义构造函数破坏:当你为 C++ 结构体添加自定义构造函数、自定义拷贝构造函数后,该结构体不再符合 标准布局类型(Standard Layout Type) / POD 类型的要求,跨 FFI 调用时的内存布局、参数传递规则都会和 C ABI 不兼容。
  • 你使用的 Windows 平台 MSVC 编译器下,对于符合 C ABI 的 POD 小结构体(比如你这个只有两个float、总大小8字节的Vec2),传值调用时会直接将结构体塞进寄存器传递;但非 POD 类型的结构体哪怕大小很小,传值时会被编译器隐式转为指针传递。而 Rust 侧用 #[repr(C)] 定义的同结构是按 C ABI 规则接收两个按值传递的结构体,两端参数传递规则不匹配,相当于把野指针/非法地址传给了 Rust 侧,触发 Segmentation fault。
解决方案

你可以选择以下任意一种方案修复:

方案1:保持 C++ 结构体为标准布局类型

移除自定义构造函数和拷贝构造函数,若需要便捷构造能力,改用静态工厂方法实现即可,此时结构体仍符合 C ABI 要求,和 Rust 侧 #[repr(C)] 定义的结构体完全兼容:

struct Vec2 {
    float X;
    float Y;

    // 用静态工厂方法替代自定义构造函数,不破坏标准布局特性
    static Vec2 make(float x, float y) {
        Vec2 res;
        res.X = x;
        res.Y = y;
        return res;
    }
};

// 使用方式
Vec2 a = Vec2::make(1.0, 2.0);
Vec2 b = Vec2::make(3.0, 4.0);

你可以通过静态断言验证结构体是否符合标准布局要求:

#include <type_traits>
static_assert(std::is_standard_layout_v<Vec2>, "Vec2 must be standard layout for FFI");

方案2:FFI 接口统一用指针传递结构体

如果你不想修改 C++ 侧的构造函数定义,可以将跨 DLL 调用的接口参数、返回值都改为结构体指针传递,避开值传递的 ABI 差异:

  • C++ 侧函数指针声明改为:Vec2* (*)(Vec2*, Vec2*)
  • Rust 侧导出函数签名改为对应指针类型即可:extern "C" fn rust(a: *const Vec2, b: *const Vec2) -> *mut Vec2

额外注意点

Rust 侧的结构体必须加 #[repr(C)] 强制指定 C 布局,同时导出函数必须标记 extern "C" 明确使用 C 调用约定,C++ 侧的函数指针也建议加 extern "C" 修饰,避免不同调用约定带来的额外问题。

内容的提问来源于stack exchange,提问作者Danguafer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 09:42:01