创建包含字符串的静态 C 结构 [英] Creating a static C struct containing strings

查看:13
本文介绍了创建包含字符串的静态 C 结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to create a dynamic library in Rust that exports a struct as a symbol that will be loaded into a C program via dlopen().

然而,我在访问结构体中的第二个字符串时遇到了一些段错误,所以我做了一个小测试程序来尝试找出我做错了什么.

However, I'm was running into some segfaults when accessing the second string in the struct, so I made a small test program to try figure out what I'm doing wrong.

这是使用rustc --crate-type dylib test.rs"编译的 Rust 代码(test.rs):

This is the Rust code (test.rs), compiled with "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",
    version: "1.0",
    description: "Test Rust Plugin"
};

这是尝试加载库 (test.c) 的 C 程序,使用gcc test.c -ldl -o test"编译:

and here is the C program that attempts to load the library (test.c), compiled with "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
", dlerror());
        return 1;
    }

    desc = (plugin_desc *) dlsym(handle, "PLUGIN_DESC");
    if (!desc) {
        printf("failed to dlsym: %s
", dlerror());
        return 1;
    }

    printf("name: %p
", desc->name);
    printf("version: %p
", desc->version);
    printf("description: %p
", desc->description);

    return 0;
}

这是输出:

name: 0x7fa59ef8d750
version: 0xc
description: 0x7fa59ef8d75c

可以看到,desc->version的地址实际上是0xc(12),也就是第一个字符串的长度.所以看起来打包到库中的结构体也包含内存地址后的字符串长度.

As you can see, the address of desc->version is actually 0xc (12), which is the length of the first string. So it looks like the struct that gets packed into the library also contains the string length after the memory address.

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

Am I using the wrong string type here? As you can see I had to also make the strings NULL terminated manually. I tried to use the CString wrapper but that does not seem to work in this case ("static items are not allowed to have destructors").

我每晚都在 Linux 上运行最新的 Rust:

I'm running the latest Rust nightly on Linux:

$ rustc --version
rustc 0.12.0-pre-nightly (f8426e2e2 2014-09-16 02:26:01 +0000)

推荐答案

切片的布局(&[T] or &str)是一个指针后跟一个长度,如 Slice 所述std::raw 模块 的结构.这就是为什么从 C 代码中读取 version 字段会显示 name 字段值的长度.(但是,请注意,切片的确切内存布局并不稳定,因此在以后的版本中可能会发生变化.在任何情况下,您都应该不要将 Rust 特定的数据类型传递给 C;只有传递原始类型(包括原始指针)和用 #[repr(C)].) 注释的类型.)

The layout of a slice (&[T] or &str) is a pointer followed by a length, as documented by the Slice struct of the std::raw module. That's why reading the version field from your C code shows the length of the name field's value. (Note, however, that the exact memory layout of slices is not considered stable, so it might change in a later version. In any case, you should not pass Rust-specific data types to C; only pass primitive types – which includes raw pointers – and types annotated with #[repr(C)].)

不幸的是,目前似乎没有办法在 Rust 中做到这一点.有一些函数可以从切片中获取原始指针,但是 静态初始化程序中不允许函数调用.正如sellibitze 在评论中所建议的,您应该在C 源文件中定义该变量.

Unfortunately, there seems to be no way to do this in Rust for now. There are functions to get raw pointers from slices, but function calls are not allowed in static initializers. As suggested by sellibitze in the comments, you should define that variable in a C source file.

这篇关于创建包含字符串的静态 C 结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆