Я использую bindgen для генерации интерфейса C для моего кода Rust. Я хочу вернуть структуру, которая содержит Option<Vec<f64>>
от Rust до C
. В Rust
я создал следующую структуру:
#[repr(C)]
pub struct mariettaSolverStatus {
lagrange: *const c_double
}
, которая связывает перевод в следующую структуру C:
/* Auto-generated structure */
typedef struct {
const double *lagrange;
} mariettaSolverStatus;
соответствующая структура в Rust
pub struct AlmOptimizerStatus {
lagrange_multipliers: Option<Vec<f64>>,
}
impl AlmOptimizerStatus {
pub fn lagrange_multipliers(&self) -> &Option<Vec<f64>> {
&self.lagrange_multipliers
}
}
Идея состоит в том, чтобы отобразить AlmOptimizerStatus
(в Rust) на mariettaSolverStatus
(в C). Когда lagrange_multipliers
равен None
, нулевой указатель будет назначен указателю в C.
Теперь в Rust у меня есть следующая функция:
#[no_mangle]
pub extern "C" fn marietta_solve(
instance: *mut mariettaCache,
u: *mut c_double,
params: *const c_double
) -> mariettaSolverStatus {
/* obtain an instance of `AlmOptimizerStatus`, which contains
* an instance of `&Option<Vec<f64>>`
*/
let status = solve(params, &mut instance.cache, u, 0, 0);
/* At this point, if we print status.langrange_multipliers() we get
*
* Some([-14.079295698854809,
* 12.321753192707693,
* 2.5355683425384417
* ])
*
*/
/* return an instance of `mariettaSolverStatus` */
mariettaSolverStatus {
lagrange: match &status.lagrange_multipliers() {
/* cast status.lagrange_multipliers() as a `*const c_double`,
* i.e., get a constant pointer to the data
*/
Some(y) => {y.as_ptr() as *const c_double},
/* return NULL, otherwise */
None => {0 as *const c_double},
}
}
}
Bindgen генерирует Cзаголовочные и библиотечные файлы, которые позволяют нам вызывать функции Rust в C. До этого момента я должен сказать, что я не получаю предупреждений от Rust.
Однако, когда я вызываю вышеуказанную функцию из C, используя автоСгенерированный интерфейс C, первый элемент из mariettaSolverStatus.lagrange
всегда 0
, тогда как все последующие элементы правильно сохранены.
Это мой код C:
#include <stdio.h>
#include "marietta_bindings.h"
int main() {
int i;
double p[MARIETTA_NUM_PARAMETERS] = {2.0, 10.0}; /* parameters */
double u[MARIETTA_NUM_DECISION_VARIABLES] = {0}; /* initial guess */
double init_penalty = 10.0;
double y[MARIETTA_N1] = {0.0};
/* obtain cache */
mariettaCache *cache = marietta_new();
/* solve */
mariettaSolverStatus status = marietta_solve(cache, u, p, y, &init_penalty);
/* prints:
* y[0] = 0 <------- WRONG!
* y[1] = 12.3218
* y[2] = 2.5356
*/
for (i = 0; i < MARIETTA_N1; ++i) {
printf("y[%d] = %g\n", i, status.lagrange[i]);
}
/* free memory */
marietta_free(cache);
return 0;
}
Я бы предположил, что каким-то образом где-то указатель выходит из области видимости.