Este código funciona bien pero da una advertencia del compilador en Rust nightly (1.2)
#[repr(C)] struct DbaxCell { cell: *const c_void } #[link(name="CDbax", kind="dylib")] extern { fn new_dCell(d: c_double) -> *const c_void; fn deleteCell(c: *const c_void); } impl DbaxCell { fn new(x: f64) -> DbaxCell { unsafe { DbaxCell { cell: new_dCell(x) } } } } impl Drop for DbaxCell { fn drop(&mut self) { unsafe { deleteCell(self.cell); } } }Se vincula a una biblioteca C y crea/elimina objetos de celda correctamente. Sin embargo, da una advertencia.
src\lib.rs:27:1: 33:2 warning: implementing Drop adds hidden state to types, possibly conflicting with `#[repr(C)]`, #[warn(drop_with_repr_extern)] on by default \src\lib.rs:27 impl Drop for DbaxCell { \src\lib.rs:28 fn drop(&mut self) { \src\lib.rs:29 unsafe { \src\lib.rs:30 deleteCell(self.cell); \src\lib.rs:31 } \src\lib.rs:32 } ¿Cuál es la forma correcta de hacer esto para garantizar que estos DbaxCell se limpien correctamente y no se avise?
Creo que estás mezclando dos conceptos. Una estructura debe ser repr(C) si desea que el diseño de la estructura se corresponda directamente con el diseño de la estructura como lo haría un compilador de C. Es decir, tiene la misma repr en memoria.
Sin embargo, no necesita eso si solo está sosteniendo un puntero sin procesar y no va a pasar la estructura de retención a C. La solución corta en este caso es "eliminar repr(C) ".
Para explicar un poco más sobre el error...
implementar Drop agrega estado oculto a los tipos, posiblemente en conflicto con
#[repr(C)]
Esto se discutió en el número 24585 . Cuando se suelta un objeto, se establece un indicador oculto (el "estado") que indica que el objeto se ha soltado, lo que evita que se produzcan varias caídas. Sin embargo, los bits ocultos significan que lo que ve en Rust no se corresponde con el aspecto que tendrían los bytes de la estructura en C, lo que niega el propósito de repr(C) .
Según lo copiado de @bluss :
Programadores de bajo nivel, no se preocupen: en el futuro, Rust eliminará esta bandera de caída por completo.
Y
Use
repr(C)para pasar estructuras en FFI, y useDropen estructuras "regulares de Rust" si es necesario. Si necesita ambos, incruste la estructurarepr(C)dentro de la estructura normal.
Imagina que tuviéramos una biblioteca que expone una estructura C con dos números de 8 bits y métodos que toman y devuelven esa estructura:
typedef struct { char a; char b; } tuple_t; tuple_t tuple_increment(tuple_t position);En este caso, definitivamente querrá imitar esa estructura y hacer coincidir la representación C en Rust:
#[repr(C)] struct Tuple { a: libc::char, b: libc::char, } Sin embargo, si la biblioteca devolvió punteros a la estructura, y nunca necesita hurgar en ella (la estructura es opaca ), entonces no necesita preocuparse por repr(C) :
void tuple_increment(tuple_t *position);Entonces puedes usar ese puntero e implementar Drop:
struct TuplePointer(*mut libc::c_void); impl Drop for TuplePointer { // Call the appropriate free function from the library }