我正在尝试学习Rust(低级编程中的新手),并希望翻译一个小型的lv2放大器(音频)插件" amp.c" (C-code)从C到Rust。我实际上让它工作(here),但当主机终止时,valgrind说" 1个块中的64个字节肯定会丢失"。我想我知道为什么会这样,但我不知道如何解决它。
在你厌倦阅读之前,这是最后一个问题:
如何静态分配包含C字符串的结构?
以下是介绍:
为什么会发生(我认为): 主机加载库并调用lv2_descriptor()
const LV2_Descriptor*
lv2_descriptor()
{
return &descriptor;
}
返回指向STATICALLY分配的类型为LV2_Descriptor的结构的指针,
static const LV2_Descriptor descriptor = {
AMP_URI,
...
};
定义为
typedef struct _LV2_Descriptor {
const char * URI;
...
} LV2_Descriptor;
为什么静态分配?在amp.c中它说:
最好静态定义描述符以避免泄漏内存 和非可移植的共享库构造函数和析构函数来清理 正确的。
但是,我将lv2_descriptor()翻译为Rust:
#[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
}
所以它没有静态分配,我永远不会释放它,我想为什么valgrind抱怨?
我该如何解决? 我试图在Rust中做同样的事情,就像C代码一样,即静态分配结构(在lv2_descriptor()之外)。目标是与lv2库完全兼容,即" ...以避免泄漏内存..."正如报价中所述,对吧?所以我尝试了类似的东西:
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, ...};
但这不编译,有错误消息,如
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();
具体问题/问题:
如何静态分配包含C字符串的结构?
答案 0 :(得分:4)
简短的回答是,你现在不是。 Future Rust可能会获得这种能力。
您可以做的是静态分配包含空指针的结构,并在调用函数时将这些空指针设置为有用的东西。 Rust有static mut
。它需要不安全的代码,不是线程安全,并且(据我所知)被视为代码异味。
就在这里,我认为这是一个解决方法,因为无法在静态中将&[T]
转换为*const T
。
static S: &'static [u8] = b"http://example.org/eg-amp_rust\n\0";
static mut desc: LV2Descriptor = LV2Descriptor {
amp_uri: 0 as *const libc::c_char, // ptr::null() isn't const fn (yet)
};
#[no_mangle]
pub extern fn lv2_descriptor(index: i32) -> *const LV2Descriptor {
let ptr = S.as_ptr() as *const libc::c_char;
unsafe {
desc.amp_uri = ptr;
&desc as *const LV2Descriptor
}
}