ptr::null() 与 null_mut() 函数
这两个函数用于创建空指针, 它指向的内存地址是 0, 常用它们来初始化或者重置原始指针.
它们的区别是:
null()
用于创建只读的空指针, 即不能通过该指针修改它指向的内存, 返回的是*const T
指针, 类似于C代码的写法:const i32* ptr = NULL;
null_mut()
用于创建可改写的空指针 (mutable pointer), 返回的是*mut T
指针, 类似于C代码的写法:i32* ptr = NULL;
use std::ptr; fn main() { let ptr: *const i32 = ptr::null(); assert!(ptr.is_null()); }
这一组函数常用于 FFI 相关的代码, 比如下面的代码片段, 调用 mmap(2)
时, 将 start_pointer
设置为空指针,
这样的话 linux 内核会自动选择合适的地址作为内存页的起始地址:
use std::ffi::c_void; use std::ptr; fn main() { let path = "/etc/passwd"; let fd = unsafe { nc::openat(nc::AT_FDCWD, path, nc::O_RDONLY, 0o644) }; assert!(fd.is_ok()); let fd = fd.unwrap(); let mut sb = nc::stat_t::default(); let ret = unsafe { nc::fstat(fd, &mut sb) }; assert!(ret.is_ok()); let offset: usize = 0; let length: usize = sb.st_size as usize - offset; // Offset for mmap must be page aligned. let pa_offset: usize = offset & !(nc::PAGE_SIZE - 1); let map_length = length + offset - pa_offset; let addr = unsafe { nc::mmap( ptr::null(), map_length, nc::PROT_READ, nc::MAP_PRIVATE, fd, pa_offset as nc::off_t, ) }; assert!(addr.is_ok()); let addr: *const c_void = addr.unwrap(); let stdout = 1; // Create buffer slice. let buf: &[u8] = unsafe { &*ptr::slice_from_raw_parts( addr.wrapping_add(offset) .wrapping_sub(pa_offset) .cast::<u8>(), length, ) }; let n_write = unsafe { nc::write(stdout, buf) }; assert!(n_write.is_ok()); assert_eq!(n_write, Ok(length as nc::ssize_t)); let ret = unsafe { nc::munmap(addr, map_length) }; assert!(ret.is_ok()); let ret = unsafe { nc::close(fd) }; assert!(ret.is_ok()); }