chr*_*ppa 8 c string struct dlopen rust
我正在尝试在Rust中创建一个动态库,它导出一个结构作为符号,将通过dlopen()加载到C程序中.
但是,当我访问结构中的第二个字符串时,我遇到了一些段错误,所以我做了一个小测试程序,试着弄清楚我做错了什么.
这是Rust代码(test.rs),使用"rustc --crate-type dylib test.rs"编译:
#[repr(C)]
pub struct PluginDesc {
name: &'static str,
version: &'static str,
description: &'static str
}
#[no_mangle]
pub static PLUGIN_DESC: PluginDesc = PluginDesc {
name: "Test Plugin\0",
version: "1.0\0",
description: "Test Rust Plugin\0"
};
Run Code Online (Sandbox Code Playgroud)
这是尝试加载库(test.c)的C程序,使用"gcc test.c -ldl -o test"编译:
#include <dlfcn.h>
#include <stdio.h>
typedef struct {
const char *name;
const char *version;
const char *description;
} plugin_desc;
int main(int argc, char **argv) {
void *handle;
plugin_desc *desc;
handle = dlopen("./libtest.so", RTLD_LOCAL | RTLD_LAZY);
if (!handle) {
printf("failed to dlopen: %s\n", dlerror());
return 1;
}
desc = (plugin_desc *) dlsym(handle, "PLUGIN_DESC");
if (!desc) {
printf("failed to dlsym: %s\n", dlerror());
return 1;
}
printf("name: %p\n", desc->name);
printf("version: %p\n", desc->version);
printf("description: %p\n", desc->description);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这是输出:
name: 0x7fa59ef8d750
version: 0xc
description: 0x7fa59ef8d75c
Run Code Online (Sandbox Code Playgroud)
如您所见,desc-> version的地址实际上是0xc(12),这是第一个字符串的长度.所以看起来像打包到库中的结构也包含内存地址之后的字符串长度.
我在这里使用错误的字符串类型吗?正如您所看到的,我还必须手动将字符串NULL终止.我试图使用CString包装器,但在这种情况下似乎不起作用("静态项目不允许有析构函数").
我在Linux上运行最新的Rust night:
$ rustc --version
rustc 0.12.0-pre-nightly (f8426e2e2 2014-09-16 02:26:01 +0000)
Run Code Online (Sandbox Code Playgroud)
正如其他答案中已经提到的,主要问题是&str对动态大小类型的引用。Rust 使用也包含长度的“胖”指针来表示内存中的此类引用或指针,而不是使用像 C 那样的简单指针const char *。
由于这些引用的内存布局(尚未)稳定,因此您无法可靠地将&str,&[T]或dyn T用作 FFI。
由于Rust 1.32(2019 年 1 月)str::as_ptr可在常量上下文中使用,因此可以轻松创建指向静态字符串的原始指针。唯一剩下的问题是原始指针默认被认为是线程不安全的。因此,您还需要实现SynconPluginDesc来断言您的结构是线程安全的。
#[repr(C)]
pub struct PluginDesc {
name: *const u8,
version: *const u8,
description: *const u8
}
unsafe impl Sync for PluginDesc {}
#[no_mangle]
pub static PLUGIN_DESC: PluginDesc = PluginDesc {
name: "Test Plugin\0".as_ptr(),
version: "1.0\0".as_ptr(),
description: "Test Rust Plugin\0".as_ptr()
};
Run Code Online (Sandbox Code Playgroud)
自 2017 年以来,还有一个null_terminated包可以使以 null 结尾的字符串更具可读性且使用更安全,但目前需要不稳定的语言功能,这些功能只能与夜间编译器一起使用:
use null_terminated::{str0_utf8, NulStr};
#[repr(C)]
pub struct PluginDesc {
name: &'static NulStr,
version: &'static NulStr,
description: &'static NulStr
}
#[no_mangle]
pub static PLUGIN_DESC: PluginDesc = PluginDesc {
name: str0_utf8!("Test Plugin"),
version: str0_utf8!("1.0"),
description: str0_utf8!("Test Rust Plugin")
};
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
594 次 |
| 最近记录: |