我有C代码桥接到.我选择先使用mem::uninitialized声明内存,然后调用C函数(UserInit)进行初始化,然后使用它(in 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);
}
Run Code Online (Sandbox Code Playgroud)
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);
}
Run Code Online (Sandbox Code Playgroud)
锈测试:
mod ffi;
use ffi::User;
fn main() {
let mut u = User::new();
u.do_something();
}
Run Code Online (Sandbox Code Playgroud)
从理论上讲,它应该输出相同的地址,但它不会:
> cargo run
Running `target/debug/learn`
in init: user addr: 0x7fff5b948b80
in do something user addr: 0x7fff5b948ba0
Run Code Online (Sandbox Code Playgroud)
这就是Rust的工作方式.
更重要的是,这也是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);
}
Run Code Online (Sandbox Code Playgroud)
in init: user addr: 0x7fff506c1600
in do something user addr: 0x7fff506c1630
Run Code Online (Sandbox Code Playgroud)
通常,您不关心容器的地址,只关心它包含的内容.
如果我堆分配
User,地址不会改变,但如果我使用Box(let u = Box::new(User::new())),它仍然会改变.
同样的事情发生在锈病和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();
}
Run Code Online (Sandbox Code Playgroud)
in init: user addr: 0x10da17000
in do something user addr: 0x10da17000
Run Code Online (Sandbox Code Playgroud)
如果你在移动到a 之前将引用传递User给C ,那么是的,地址将在移动到地址时改变.这相当于:BoxBox
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);
}
Run Code Online (Sandbox Code Playgroud)
请注意,Rust(和其他语言)允许执行RVO.但是,我认为打印出地址会取消此优化的资格,因为如果启用了RVO,行为将会改变.您需要查看调试器或生成的程序集.
| 归档时间: |
|
| 查看次数: |
276 次 |
| 最近记录: |