-1

我已经为 Rust 中的相机库编写了一个包装器,它命令和操作一个 16 位相机,并且还使用 bindgen 将图像保存到文件中。一旦我命令开始曝光(基本上是告诉相机拍摄图像),我可以使用以下形式的函数抓取图像:

pub fn GetQHYCCDSingleFrame(
handle: *mut qhyccd_handle,
w: *mut u32,
...,
imgdata: *mut u16,) -> u32 //(u32 is a retval)

在 C++ 中,这个函数是:

uint32_t STDCALL GetQHYCCDSingleFrame(qhyccd_handle: *handle, ..., uint8_t *imgdata)

在 C++ 中,我可以传入表单的缓冲区,imgdata = new unsigned char[length_buffer]该函数将使用来自相机的图像数据填充缓冲区。

在 Rust 中,类似地,我可以mut_ptr以 Vec: 的形式传入一个缓冲区let mut buffer: Vec<u16> = vec![0u16; length_buffer]

目前,我构建代码的方式是有一个主结构,其中包含图像的宽度和高度、相机句柄等设置,包括图像缓冲区。该结构已被初始化为mut

let mut main_settings = MainSettings {
width: 9600,
...,
buffer: vec![0u16; length_buffer],
}

当将它传递给GetQHYCCDSingleFrame函数时,我相应地传递它:

let retval = unsafe { GetQHYCCDSingleFrame(main_settings.cam_handle, ..., main_settings.image_buffer.as_mut_ptr()) };

当我使用or 构建程序并使用 orcargo build运行cargo build --release时,此代码可以完美运行。程序开始曝光,等待曝光完成,然后“获取”帧并用图像数据正确填充缓冲区。cargo runcargo run --release

但是,最初在编写程序时,我错误地将 GetQHYCCDSingleFrame 函数声明为:

pub fn GetQHYCCDSingleFrame(
handle: *mut qhyccd_handle,
w: *mut u32,
...,
imgdata: &mut [u16],) -> u32 //(u32 is a retval)

(注意 imgdata 类型从*mut u16到的变化&mut [u16])。

当我将相同的先前缓冲区作为切片而不是指针传递时:

let retval = unsafe { GetQHYCCDSingleFrame(main_settings.cam_handle, ..., &mut main_settings.image_buffer) };

当我使用(dev build with 0 optimizations) 构建cargo build并运行程序时,该程序运行良好。cargo run该函数和调用有效,并且填充了图像缓冲区。cargo build --release但是,当我使用或运行它时,该程序在 GetQHYCCDSingleFrame 处出现段错误cargo run --release (使用 发布构建opt-level = 3)。

使用rust-gdb,段错误是:

Thread 1 "qsc" received signal SIGSEGV, Segmentation fault.
_memmove_sse2_unaligned_erms()
at ../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:538
538
../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S: No such file or directory.

我在 Rust 优化方面没有太多经验,也不太了解 Rust 正在做什么优化以导致程序在没有优化的情况下完美运行时出现段错误。我确实明白正确的做法是像现在一样发送 a mut_ptr,一切正常,但回首往事,我想了解为什么以前的错误程序有效但只在开发版本而不是发布版本?是否有可能理解 C++ 代码中的上下文以及那里的要求?还是发生了其他事情?

如果有更多信息可能有助于理解,我也很乐意提供。谢谢!

4

1 回答 1

2

您的 FFI 函数签名无效,因为您使用了无效的 ABI:

pub fn GetQHYCCDSingleFrame(
handle: *mut qhyccd_handle,
w: *mut u32,
...,
imgdata: *mut u16,) -> u32 //(u32 is a retval)

您应该首先阅读有关 FFI 的信息。

https://doc.rust-lang.org/nomicon/ffi.html

https://doc.rust-lang.org/reference/items/external-blocks.html

默认情况下,Rust 对外部函数使用“C”ABI,但你的函数应该使用stdcallABI(假设你的 C++ 代码)。您可以阅读更多有关此内容的信息。

例如

extern "stdcall" {
 pub fn GetQHYCCDSingleFrame(
   handle: *mut qhyccd_handle,
   w: *mut u32,
   ...,
   imgdata: *mut u16,) -> u32;
}
于 2021-11-12T15:43:06.503 回答