Vector 包含数据但报告长度为 0,可由某些函数访问
Vector contains data but reports length is 0, can be accessed by some functions
我用 Rust 为相机库编写了一个包装器,它可以命令和操作相机,还可以使用 bindgen 将图像保存到文件中。一旦我命令曝光开始(基本上告诉相机拍摄图像),我就可以使用以下形式的函数抓取图像:
pub fn GetQHYCCDSingleFrame(
handle: *mut qhyccd_handle,
w: *mut u32,
...,
imgdata: &mut [u8],) -> u32 //(u32 is a retval)
在 C++ 中,这个函数是:
uint32_t STDCALL GetQHYCCDSingleFrame(qhyccd_handle: *handle, ..., uint8_t *imgdata)
在 C++ 中,我可以传入 imgdata = new unsigned char[length_buffer]
形式的缓冲区,该函数会用来自相机的图像数据填充缓冲区。
在 Rust 中,类似地,我可以以 Vec 的形式传入缓冲区:let mut buffer: Vec<u8> = Vec::with_capacity(length_buffer)
.
目前,我构建代码的方式是有一个主结构体,其中包含图像的宽度和高度、相机手柄等设置,包括图像缓冲区。该结构已初始化为 mut
为:
let mut main_settings = MainSettings {
width: 9600,
...,
buffer: Vec::with_capacity(length_buffer),
}
我写了一个单独的函数,将主结构作为参数并调用 GetQHYCCDSingleFrame 函数:
fn grab_image(main_settings: &mut MainSettings) {
let retval = unsafe { GetQHYCCDSingleFrame(main_settings.cam_handle, ..., &mut main_settings.image_buffer) };
}
调用此函数后,如果我立即检查 main_settings.image_buffer 的长度和容量:
println!("Elements in buffer are {}, capacity of buffer is {}.", main_settings.image_buffer.len(), main_settings.image_buffer.capacity());
长度为 0,容量为 buffer_length。同样,打印任何索引,例如 main_settings.image_buffer[0]
或 1 会导致恐慌退出,显示 len is 0
.
这会让我认为 GetQHYCCDSingleFrame
代码无法正常工作,但是,当我使用 fitsio
and hdu.write_region
(fitsio docs linked here) 将 image_buffer 保存到文件时,我使用:
let ranges = [&(x_start..(x_start + roi_width)), &(y_start..(y_start+roi_height))];
hdu.write_region(&mut fits_file, &ranges, &main_settings.image_buffer).expect("Could not write to fits file");
这会以正确的大小将实际图像保存到文件中,并且是一张非常精美的图像(如果我使用 C++ 程序拍摄,它的外观就是这样)。但是,当我尝试打印缓冲区时,由于某种原因它是空的,但 hdu.write_region
代码能够以某种方式访问数据。
目前,我的(不好的)解决方法是创建另一个向量,它从保存的文件中读取数据并保存到缓冲区,然后缓冲区具有正确数量的元素:
main_settings.new_buffer = hdu.read_region(&mut fits_file, &ranges).expect("Couldn't read fits file");
为什么我根本无法访问原始缓冲区,为什么它报告长度为 0,而 hdu.write_region
函数可以从某处访问数据?它究竟从哪里访问数据,我如何才能正确访问它?我对借用和引用有点陌生,所以我相信我可能在 borrowing/referencing 缓冲区中做错了什么,或者是其他什么?
抱歉说来话长,但细节可能对这里的一切都很重要。谢谢!
嗯,首先,你需要知道 Vec<u8>
和 &mut [u8]
与 C 或 C++ 的 uint8_t *
并不完全相同。主要区别在于 Vec<u8>
和 &mut [u8]
自身保存了数组或切片的大小,而 uint8_t *
没有。相当于 C/C++ 指针的 Rust 是原始指针,如 *mut [u8]
。原始指针可以安全构建,但需要 unsafe
才能使用。但是,即使它们是不同的类型,智能指针 &mut [u8]
也可以毫无问题地转换为原始指针。
其次,Vec
的容量与其大小不同。实际上,为了获得良好的性能,Vec
分配的内存比您使用的多,以避免在添加到 vector 中的每个新元素上重新分配。然而,长度是所用零件的尺寸。在您的情况下,您要求 Vec
分配一个长度为 length_buffer
的堆 space,但您没有告诉他们考虑使用任何已分配的 space ,所以初始长度为 0。由于 C++ 不知道 Vec
并且只使用原始指针,它不能更改写在 Vec
中的长度,它保持为 0。因此恐慌。
要解决它,我看到了多种解决方案:
将 Vec::with_capacity(length_buffer)
更改为 vec![0; length_buffer]
,明确要求从头开始 length_buffer
的长度
使用 unsafe
代码显式设置 Vec
的长度而不触及内部内容(使用 Vec::from_raw_parts
)。 可能比第一个解决方案更快,但我不确定。
使用 Box<[u8; length_buffer]>
,它类似于 Vec
,但没有重新分配,长度为容量
如果你的 length_buffer
在编译时是常量,使用 [u8; length_buffer]
会更有效率,因为不需要分配,但它有缺点,你可能知道
我用 Rust 为相机库编写了一个包装器,它可以命令和操作相机,还可以使用 bindgen 将图像保存到文件中。一旦我命令曝光开始(基本上告诉相机拍摄图像),我就可以使用以下形式的函数抓取图像:
pub fn GetQHYCCDSingleFrame(
handle: *mut qhyccd_handle,
w: *mut u32,
...,
imgdata: &mut [u8],) -> u32 //(u32 is a retval)
在 C++ 中,这个函数是:
uint32_t STDCALL GetQHYCCDSingleFrame(qhyccd_handle: *handle, ..., uint8_t *imgdata)
在 C++ 中,我可以传入 imgdata = new unsigned char[length_buffer]
形式的缓冲区,该函数会用来自相机的图像数据填充缓冲区。
在 Rust 中,类似地,我可以以 Vec 的形式传入缓冲区:let mut buffer: Vec<u8> = Vec::with_capacity(length_buffer)
.
目前,我构建代码的方式是有一个主结构体,其中包含图像的宽度和高度、相机手柄等设置,包括图像缓冲区。该结构已初始化为 mut
为:
let mut main_settings = MainSettings {
width: 9600,
...,
buffer: Vec::with_capacity(length_buffer),
}
我写了一个单独的函数,将主结构作为参数并调用 GetQHYCCDSingleFrame 函数:
fn grab_image(main_settings: &mut MainSettings) {
let retval = unsafe { GetQHYCCDSingleFrame(main_settings.cam_handle, ..., &mut main_settings.image_buffer) };
}
调用此函数后,如果我立即检查 main_settings.image_buffer 的长度和容量:
println!("Elements in buffer are {}, capacity of buffer is {}.", main_settings.image_buffer.len(), main_settings.image_buffer.capacity());
长度为 0,容量为 buffer_length。同样,打印任何索引,例如 main_settings.image_buffer[0]
或 1 会导致恐慌退出,显示 len is 0
.
这会让我认为 GetQHYCCDSingleFrame
代码无法正常工作,但是,当我使用 fitsio
and hdu.write_region
(fitsio docs linked here) 将 image_buffer 保存到文件时,我使用:
let ranges = [&(x_start..(x_start + roi_width)), &(y_start..(y_start+roi_height))];
hdu.write_region(&mut fits_file, &ranges, &main_settings.image_buffer).expect("Could not write to fits file");
这会以正确的大小将实际图像保存到文件中,并且是一张非常精美的图像(如果我使用 C++ 程序拍摄,它的外观就是这样)。但是,当我尝试打印缓冲区时,由于某种原因它是空的,但 hdu.write_region
代码能够以某种方式访问数据。
目前,我的(不好的)解决方法是创建另一个向量,它从保存的文件中读取数据并保存到缓冲区,然后缓冲区具有正确数量的元素:
main_settings.new_buffer = hdu.read_region(&mut fits_file, &ranges).expect("Couldn't read fits file");
为什么我根本无法访问原始缓冲区,为什么它报告长度为 0,而 hdu.write_region
函数可以从某处访问数据?它究竟从哪里访问数据,我如何才能正确访问它?我对借用和引用有点陌生,所以我相信我可能在 borrowing/referencing 缓冲区中做错了什么,或者是其他什么?
抱歉说来话长,但细节可能对这里的一切都很重要。谢谢!
嗯,首先,你需要知道 Vec<u8>
和 &mut [u8]
与 C 或 C++ 的 uint8_t *
并不完全相同。主要区别在于 Vec<u8>
和 &mut [u8]
自身保存了数组或切片的大小,而 uint8_t *
没有。相当于 C/C++ 指针的 Rust 是原始指针,如 *mut [u8]
。原始指针可以安全构建,但需要 unsafe
才能使用。但是,即使它们是不同的类型,智能指针 &mut [u8]
也可以毫无问题地转换为原始指针。
其次,Vec
的容量与其大小不同。实际上,为了获得良好的性能,Vec
分配的内存比您使用的多,以避免在添加到 vector 中的每个新元素上重新分配。然而,长度是所用零件的尺寸。在您的情况下,您要求 Vec
分配一个长度为 length_buffer
的堆 space,但您没有告诉他们考虑使用任何已分配的 space ,所以初始长度为 0。由于 C++ 不知道 Vec
并且只使用原始指针,它不能更改写在 Vec
中的长度,它保持为 0。因此恐慌。
要解决它,我看到了多种解决方案:
将
Vec::with_capacity(length_buffer)
更改为vec![0; length_buffer]
,明确要求从头开始length_buffer
的长度使用
unsafe
代码显式设置Vec
的长度而不触及内部内容(使用Vec::from_raw_parts
)。 可能比第一个解决方案更快,但我不确定。使用
Box<[u8; length_buffer]>
,它类似于Vec
,但没有重新分配,长度为容量如果你的
length_buffer
在编译时是常量,使用[u8; length_buffer]
会更有效率,因为不需要分配,但它有缺点,你可能知道