Rust 为什么一个对象的地址会随着方法的不同而变化?
我有C代码要桥接。我选择使用Rust 为什么一个对象的地址会随着方法的不同而变化?,rust,Rust,我有C代码要桥接。我选择使用mem::uninitialized首先声明内存,然后调用C函数(UserInit)进行初始化,然后使用它(在UserDoSomething中) 奇怪的是对象的地址在UserInit和UserDoSomething中不同。为什么它会这样 C代码: typedef struct { char* name; int32_t age; } User; void UserInit(User* u){ printf("in init: user add
mem::uninitialized
首先声明内存,然后调用C函数(UserInit
)进行初始化,然后使用它(在UserDoSomething
中)
奇怪的是对象的地址在UserInit
和UserDoSomething
中不同。为什么它会这样
C代码:
typedef struct {
char* name;
int32_t age;
} User;
void
UserInit(User* u){
printf("in init: user addr: %p\n", u);
}
void
UserDoSomething(User* u){
printf("in do something user addr: %p\n", u);
}
void
UserDestroy(User* u){
free(u->name);
}
英国外交部:
use std::mem;
use std::os::raw::c_char;
use std::ffi::CString;
#[repr(C)]
pub struct User{
pub name: *const c_char,
pub age: i32,
}
impl User {
pub fn new()-> User {
let ret: User = unsafe { mem::uninitialized() };
unsafe {
UserInit(&mut ret as *mut User)
}
ret
}
pub fn do_something(&mut self){
unsafe {
UserDoSomething(self as *mut User)
}
}
}
extern "C" {
pub fn UserInit(u:*mut User);
pub fn UserDoSomething(u:*mut User);
pub fn UserDestroy(u:*mut User);
}
锈蚀试验:
mod ffi;
use ffi::User;
fn main() {
let mut u = User::new();
u.do_something();
}
理论上,它应该输出相同的地址,但它不:
>货物运输
运行“目标/调试/学习”`
在init中:用户地址:0x7fff5b948b80
在do something用户地址中:0x7fff5b948ba0
锈就是这样起作用的。对象没有标识;将它们移出函数(例如User::new
)会将它们移动到新位置,从而更改它们的地址
如果您的C代码需要稳定的地址,则需要使Rust用户
包含一个框
或原始指针
锈就是这样起作用的 除此之外,C也是这样工作的: 通常,您不关心容器的地址,只关心它包含的内容 如果我堆分配
User
,地址不会更改,但是如果我使用Box
(让u=Box::new(User::new())
),地址仍然会更改
Rust和C中也会发生同样的情况。框
或用户*
本身的地址会改变。框
或用户*
的值(指向的对象)将保持一致
mod ffi {
use std::mem;
use std::os::raw::c_char;
#[repr(C)]
pub struct User {
pub name: *const c_char,
pub age: i32,
}
impl User {
pub fn new() -> Box<User> {
let mut ret: Box<User> = Box::new(unsafe { mem::uninitialized() });
unsafe { UserInit(&mut *ret) }
ret
}
pub fn do_something(&mut self) {
unsafe { UserDoSomething(self) }
}
}
extern "C" {
pub fn UserInit(u: *mut User);
pub fn UserDoSomething(u: *mut User);
}
}
use ffi::User;
fn main() {
let mut u = User::new();
u.do_something();
}
如果在移动到框
之前将对用户
的引用传递到C,则是的,地址将在移动到框
时更改。这相当于:
User rust_like_new(void) {
User u;
UserInit(&u);
return u;
}
int main(int argc, char *argv[]) {
User u = rust_like_new();
User *u2 = malloc(sizeof(User));
*u2 = u;
UserDoSomething(u2);
}
请注意,Rust(和其他语言)允许执行。但是,我相信打印出地址将取消此优化的资格,因为如果启用RVO,行为将发生变化。您需要查看调试器或生成的程序集。谢谢!我发现同一范围内obj的引用具有相同的地址。可能我必须编写一个显式方法User::Init(&mut self)
来处理它。你如何看待这种方法?为什么在C端的地址很重要?一个后续问题:好的观点!一个主要的区别是,如果我堆alloc User,地址就不会改变。但如果我像这样在rust中使用Box:让u=Box::new(User::new())
,它仍然会发生变化。回答很好。非常感谢你的详细解释。
User rust_like_new(void) {
User u;
UserInit(&u);
return u;
}
int main(int argc, char *argv[]) {
User u = rust_like_new();
User *u2 = malloc(sizeof(User));
*u2 = u;
UserDoSomething(u2);
}