Я написал функцию на C с этой подписью:
write_stuff(char **pages, uint32 page_count);
pages
будет массивом из 128 элементов, где каждый элемент либо NULL, либо указывает на массив символов размером 8192 байта. Итак, массив массивов с фиксированными, известными размерами.
Мне нужно заполнить массивы в Rust и передать их функции C. Когда я генерирую подпись Rust с помощью bindgen, получается следующее:
extern "C" {
pub fn write_stuff(pages: *mut *mut ::std::os::raw::c_char, page_count: u32,);
}
Теперь, как мне объявить переменную в Rust, которую я могу заполнить и передать этой функции?
Я пробовал это:
let mut pages = [Option <[u8; 8192]>; 128];
но он не компилируется.
Это компилируется:
type MyPage = Option<[u8; 8192]>;
let myarray: [MyPage; 128] = [None; 128];
но я не понимаю, будет ли он хранить данные в правильном формате или как правильно их использовать:
let pages: *mut *mut ::std::os::raw::c_char = myarray.as_mut_ptr() as // what goes here?;
Я считаю, что тип Rust, который вы ищете, это &[Option<&[u8; 8192]>]
.
Версия C использует двойной указатель, поэтому вам нужно убедиться, что внутренний тип является ссылкой. Option<&T>
показывает, что ссылка может принимать значение NULL, а оптимизация нулевого указателя гарантирует, что она имеет тот же размер, что и T
.
Я проверил, что приведенный ниже код работает должным образом, но я не уверен на 100%, что это преобразование типа правильно поэтому я был бы осторожен, используя это в производственном коде.
Rust main.rs
#[link(name = "mylib")]
extern "C" {
pub fn write_stuff(pages: *mut *mut ::std::os::raw::c_char, page_count: u32);
}
pub fn write_stuff_rust(pages: &[Option<&[u8; 8192]>]) {
unsafe { write_stuff(pages.as_ptr() as *mut _, pages.len() as u32) }
}
fn main() {
let page1: [u8; 8192] = [b'a'; 8192];
let page3: [u8; 8192] = [b'b'; 8192];
let page4: [u8; 8192] = [b'c'; 8192];
let page7: [u8; 8192] = [b'd'; 8192];
let pages: Vec<Option<&[u8; 8192]>> = vec![
Some(&page1),
None,
Some(&page3),
Some(&page4),
None,
None,
Some(&page7),
];
write_stuff_rust(&pages);
}
C mylib.c
#include <stdio.h>
#include <stdint.h>
void write_stuff(char **pages, uint32_t page_count) {
for (uint32_t i = 0; i < page_count; i++) {
printf("%d=%p\n", i, pages[i]);
if (pages[i]) {
for (size_t j = 0; j < 8192; j++) {
putchar(pages[i][j]);
}
putchar('\n');
} else {
puts("<empty>");
}
}
}
Однако это правильно: а) лучше использовать &[Option<&[u8; 8192]>; 128]
(дает компилятору больше знаний, а значит, улучшает оптимизацию). б) Если код C изменяет ссылки, это UB (поскольку они созданы из общих ссылок), а если нет, то лучше изменить их на *const
(или const *
в C).
Спасибо, это выдающееся. Вы сделали все возможное.