将Rust指针传递给C时,我应该得到0x1吗?

Mic*_*son 1 c ffi rust

我正在尝试在Rust中实现一个基本库,它创建一个对象并将其指针返回给C.我得到的指针看起来不像它在堆上 - 当我打印它时我得到0x1:

use std::fmt;

pub struct SndbDB {}

impl SndbDB {
    fn new() -> SndbDB {
        SndbDB {}
    }
}

impl fmt::Display for SndbDB {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "(sndb_db)")
    }
}

// Implement a destructor just so we can see when the object is destroyed.
impl Drop for SndbDB {
    fn drop(&mut self) {
        println!("[rust] dropping {}", self);
    }
}

#[no_mangle]
pub extern "C" fn sndb_db_create() -> *mut SndbDB {
    let _db = Box::into_raw(Box::new(SndbDB::new()));
    println!("[rust] creating DB {:?}", _db);
    _db
}

#[no_mangle]
pub unsafe extern "C" fn sndb_db_destroy(ptr: *mut SndbDB) {
    println!("[rust] destroying DB {:?}", ptr);
    Box::from_raw(ptr); // Rust drops this for us.
}
Run Code Online (Sandbox Code Playgroud)

C调用代码也是微不足道的:

typedef struct sndb_db sndb_db;

sndb_db * sndb_db_create(void);
void sndb_db_destroy(sndb_db* db);

void test_baseapi__create_and_destroy_db(void)
{
    sndb_db * db = sndb_db_create();
    printf("[C] Got db=%p\n",db);
    sndb_db_destroy(db);
    printf("[C] db should be dead by now...\n");
}
Run Code Online (Sandbox Code Playgroud)

除了指针位置之外的所有输出都是我期望的:

[rust] creating DB 0x1
[C] Got db=0x1
[rust] destroying DB 0x1
[rust] dropping (sndb_db)
[C] db should be dead by now...
Run Code Online (Sandbox Code Playgroud)

我知道在Rust中分配的内存需要被Rust解除分配 - 但是我仍然感到惊讶它使用的位置0x1- 我做错了什么,发生了什么奇怪的事情,或者这一切都好吗?

Mic*_*son 6

看起来这是Rust的优化,因为SndbDBstruct没有状态.

添加一个i: u32字段并将其传递给构造函数和C代码然后我得到:

[rust] creating DB 0x7fff2fe00000
[C] Got db=0x7fff2fe00000
[rust] destroying DB 0x7fff2fe00000
[rust] dropping (sndb_db i=123)
[C] db should be dead by now...
Run Code Online (Sandbox Code Playgroud)

但是我仍然希望找到一个官方消息来支持这个猜测.

  • Rust避免实际*为零大小的类型分配内存.相反,它使用"占位符"指针值.这就是这里发生的事情.与`Vec`类似的事情:如果你有一个零大小值的向量,它永远不会分配任何内存,只跟踪你已经推送了多少元素. (3认同)
  • 我不认为这是在任何地方记录的,因为它是一个实现细节.有[`EMPTY`](https://github.com/rust-lang/rust/blob/b6f554b6dc972608761db93a375bcb0e89155e1d/src/liballoc/heap.rs#L231-L237),最近,[`Unique :: empty`] (https://doc.rust-lang.org/1.19.0/src/core/ptr.rs.html#1011).考虑到所涉及的开销,使用内存分配器获取唯一ID非常简洁. (3认同)