创建包含字符串的静态C结构

创建包含字符串的静态C结构,c,string,struct,rust,dlopen,C,String,Struct,Rust,Dlopen,我试图在Rust中创建一个动态库,它将结构作为符号导出,并通过dlopen()加载到C程序中 然而,在访问结构中的第二个字符串时,我遇到了一些segfault,所以我制作了一个小测试程序,试图找出我做错了什么 这是Rust代码(test.rs),用“rustc--cratetype dylib test.rs”编译: 下面是试图加载库(test.C)的C程序,它使用“gcc test.C-ldl-o test”编译: 如您所见,desc->version的地址实际上是0xc(12),这是第一个字

我试图在Rust中创建一个动态库,它将结构作为符号导出,并通过dlopen()加载到C程序中

然而,在访问结构中的第二个字符串时,我遇到了一些segfault,所以我制作了一个小测试程序,试图找出我做错了什么

这是Rust代码(test.rs),用“rustc--cratetype dylib test.rs”编译:

下面是试图加载库(test.C)的C程序,它使用“gcc test.C-ldl-o test”编译:

如您所见,desc->version的地址实际上是0xc(12),这是第一个字符串的长度。因此,看起来打包到库中的结构也包含内存地址后的字符串长度

我在这里使用了错误的字符串类型吗?如您所见,我还必须手动使字符串以NULL结尾。我尝试使用CString包装器,但在这种情况下似乎不起作用(“静态项不允许有析构函数”)

我正在Linux上运行最新的Rust nightly:

$ rustc --version
rustc 0.12.0-pre-nightly (f8426e2e2 2014-09-16 02:26:01 +0000)
切片的布局(
&[T]
&str
)是一个后跟长度的指针,如所述。这就是为什么从C代码中读取
version
字段会显示
name
字段值的长度。(但是,请注意,片的确切内存布局并不稳定,因此在以后的版本中可能会发生更改。在任何情况下,都不应将特定于锈蚀的数据类型传递给C;只应传递基本类型(包括原始指针)和用
#[repr(C)]
注释的类型)


编辑:不幸的是,目前在Rust中似乎没有办法做到这一点。有一些函数可以从切片中获取原始指针,但是。正如sellibitze在评论中所建议的,您应该在C源文件中定义该变量。

简单的回答是,您不能静态地分配这样的结构。未来的锈菌可能会获得这种能力

您可以做的是静态地分配一个包含空指针的结构,并在调用函数时将这些空指针设置为有用的对象。锈菌具有
静态mut
。它需要不安全的代码根本不是线程安全的,并且(据我所知)被认为是代码气味

在这里,我认为这是一个解决办法,在静态中不能将<代码>和[t] < /代码>转换成<代码> *const t/s>。

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
     }
}

您是否尝试过将
*i8
指针放在结构中?看起来锈字符串不仅仅是
char*
。是否有一个.h文件包含用于链接C的rust字符串的定义?字节文字(类型
&[u8]
)是否真的强制执行
*常量u8
?不幸的是,这也不起作用。我得到了错误“expected
*const i8
,found
&'static[u8]
(expected i8,found vector)”,但是当将类型更改为“&'static[u8]”使其编译时,它与原始代码有相同的问题。@chrippa:在片上有一个
as_ptr
方法。但是我认为你不能把它作为静态初始化的一部分。我看到的唯一解决方案是编写一个C文件,编译该文件并将其链接到Rust code.wut的其余部分。当我在play.rust-lang.org上测试这个时,我没有
main
方法,它抱怨了一些其他错误,但没有在这个上。使用
main
方法,它确实会抱怨。我更改了我的答案,因为现在似乎不可能这样做。
Slice
的表示不能保证不会更改:与常规的rust结构一样,字段的顺序并不重要。因此,Rust此时无法为您提供所需的担保——不要跨越ffi边界传递
&str
name: 0x7fa59ef8d750
version: 0xc
description: 0x7fa59ef8d75c
$ rustc --version
rustc 0.12.0-pre-nightly (f8426e2e2 2014-09-16 02:26:01 +0000)
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
     }
}