Próbuję uczyć Rusta (początkującego programistę niskiego poziomu) i chcę przetłumaczyć małą wtyczkę wzmacniacza lv2 (audio) "amp.c" (C-code) od C do Rusta . Właściwie to działa (here), ale kiedy host kończy, valgrind mówi, że " 64 bajty w 1 blokach są zdecydowanie stracone". Myślę, że wiem, dlaczego tak się dzieje, ale nie wiem, jak to naprawić.statyczna struktura z ciągami C dla wtyczki lv2
Przed znudzi czytanie, tu jest ostatnie pytanie:
Jak statycznie przydziela struct, który zawiera ciąg C?
I tu jest wprowadzenie:
Dlaczego zdarza się (chyba): Host ładuje bibliotekę i wzywa lv2_descriptor()
const LV2_Descriptor*
lv2_descriptor()
{
return &descriptor;
}
która zwraca wskaźnik do statycznie przydzielonego struktury typu LV2_Descriptor,
static const LV2_Descriptor descriptor = {
AMP_URI,
...
};
, który jest zdefiniowany jako
typedef struct _LV2_Descriptor {
const char * URI;
...
} LV2_Descriptor;
Dlaczego jest statycznie przydzielony? W amp.c mówi:
Najlepiej jest określić deskryptory statycznie, aby uniknąć wycieka pamięć i innych przenośnych bibliotek współdzielonych konstruktory i destruktory do czyszczenia się prawidłowo.
Jednak przetłumaczyłem lv2_descriptor(), aby Rust jako:
#[no_mangle]
pub extern fn lv2_descriptor(index:i32) -> *const LV2Descriptor {
let s = "http://example.org/eg-amp_rust";
let cstr = CString::new(s).unwrap();
let ptr = cstr.as_ptr();
mem::forget(cstr);
let mybox = Box::new(LV2Descriptor{amp_uri: ptr}, ...);
let bxptr = &*mybox as *const LV2Descriptor;
mem::forget(mybox);
return bxptr
}
Więc to nie jest alokowany statycznie i nigdy go za darmo, to myślę, dlaczego valgrind narzeka?
Jak mogę to rozwiązać? Próbuję zrobić to samo w Rust, jak kod C, to znaczy statycznie przydzielić strukturę (poza z lv2_descriptor()). Celem jest być w pełni kompatybilny z biblioteką lv2, tj. "... aby uniknąć wycieku pamięci ..." itp., Jak to podano w cytacie, prawda? Więc próbowałem coś takiego:
static ptr1: *const u8 = (b"example.org/eg-amp_rust\n\0").as_ptr();
static ptr2: *const libc::c_char = ptr1 as *const libc::c_char;
static desc: LV2Descriptor = LV2Descriptor{amp_uri: ptr2, ...};
Ale to nie skompilować, istnieją komunikaty o błędach, takich jak
src/lib.rs:184:26: 184:72 error: the trait `core::marker::Sync` is not implemented for the type `*const u8` [E0277]
src/lib.rs:184 static ptr1: *const u8 = b"http://example.org/eg-amp_rust\n\0".as_ptr();
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/lib.rs:184:26: 184:72 note: `*const u8` cannot be shared between threads safely
src/lib.rs:184 static ptr1: *const u8 = b"http://example.org/eg-amp_rust\n\0".as_ptr();
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/lib.rs:184:26: 184:72 error: static contains unimplemented expression type [E0019]
src/lib.rs:184 static ptr1: *const u8 = b"http://example.org/eg-amp_rust\n\0".as_ptr();
specyficzny problem/pytanie:
Jak statycznie przydziela struct że zawiera ciąg C?
Nowicjusz w programowaniu niskiego poziomu * kto używa valgrind, rozumie jego raport i śledzi wyciek pamięci? Podaję ci kapelusz, proszę pana! –
@Shepmaster: Dzięki, nie widziałem tego, to rzeczywiście ten sam problem. Wypróbowałem odpowiedź Kera i działa idealnie, więc może możemy dostosować odpowiedź Kerera do pierwotnego pytania i usunąć to? – poidl
@MatthieuM .: Cóż, musiałem napisać program Fortran ~ 1000 linii raz do pracy, i musiałem użyć valgrind tam ... Myślę, że w porównaniu do większości ludzi tutaj wciąż jestem całkiem początkującym :) – poidl