gpt4 book ai didi

rust - 为什么对象的地址会在方法之间发生变化?

转载 作者:行者123 更新时间:2023-11-29 07:56:42 25 4
gpt4 key购买 nike

我有要连接的 C 代码。我选择使用 mem::uninitialized 先声明内存,然后调用 C 函数 (UserInit) 进行初始化,然后使用它(在 UserDoSomething)。

奇怪的是对象的地址在 UserInitUserDoSomething 中是不同的。为什么它会这样?

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

Rust FFI:

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

使用rust 测试:

mod ffi;

use ffi::User;

fn main() {
let mut u = User::new();
u.do_something();
}

理论上,它应该输出相同的地址,但事实并非如此:

> cargo run
Running `target/debug/learn`
in init: user addr: 0x7fff5b948b80
in do something user addr: 0x7fff5b948ba0

最佳答案

That's just how Rust works.

不仅如此,C 的工作方式也是如此:

#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>

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

User rust_like_new(void) {
User u;
UserInit(&u);
return u;
}

int main(int argc, char *argv[]) {
User u = rust_like_new();
UserDoSomething(&u);
}
in init: user addr:        0x7fff506c1600
in do something user addr: 0x7fff506c1630

通常,您不关心容器的地址,只关心它包含什么。

If I heap allocate User, the address won't change, but if I use Box (let u = Box::new(User::new())), it still changes.

同样的事情发生在 Rust 和 C 中。Box<User>地址User *本身就会改变。 Box<User>(指向的东西)或 User *将保持一致。

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();
}
in init: user addr:        0x10da17000
in do something user addr: 0x10da17000

如果您传递对 User 的引用到 C before 它被移动到 Box , 那么是的,地址将在移入 Box 时发生变化.这相当于:

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被执行。但是,我认为打印出地址 会取消此优化的资格,因为如果启用 RVO,行为会发生变化。您需要查看调试器或生成的程序集。

关于rust - 为什么对象的地址会在方法之间发生变化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38302270/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com