目录:
- 导入外部符号
- C++与Rust数据类型对应关系
- 使用slice直接读写指针内容
- 写指针
- 读指针
- 判断指针是否为NULL/nullptr
- 返回nullptr/NULL
1. 导入外部符号
通常,C/C++通过#include
导入外部符号(不考虑extern
和前置声明的情况)。而Rust没头文件,使用use
导入外部符号。示例如下:
// C++
#include "OpenGLES/ES2/gl.h"
#include "Framebuffer.h"
// Rust
use OpenGLES::ES2::gl::*;
use Framebuffer::*;
使用*
导入所有符号虽然方便,但是会消耗更多编译时间,因此枚举当前文件使用的符号是更好的实践。
进阶:self
关键字可导入mod.rs文件或者与上一次目录同名的rs文件。示例如下:
// 此处self表示rc.rs,因为rc模块内部没切成多个目录组织源码
use std::rc::{self, Rc, Weak};
// 此处self表示rc目录下的mod.rs文件
use std::io::{self, Read, Write};
2. C++与Rust数据类型对应关系
C++以64位系统为编译目标时数据类型与Rust对应关系如下所示。
C++ | Rust |
---|---|
void | std::os::raw::c_void |
char | i8 |
short | i16 |
int | i32 |
long | i64 |
unsigned char | u8 |
unsigned short | u16 |
unsigned int | u32 |
unsigned long | u64 |
size_t | usize |
float | f32 |
double | f64 |
bool | bool |
char* | &str |
std::string | String |
其实,char对i8或u8都行,满足8bit存储空间即可,映射成u8更方便用String和Vec操作。
3. 使用slice直接读写指针内容
3.1 写指针
// C++
const int COUNT = 100;
int *int_ptr = new int[COUNT];
for (int i = 0; i < COUNT; ++i) {
int_ptr[i] = i;
}
将上述C++申请的ptr指针传递到Rust进行写入,最差的办法是在Rust内部创建一个长度相同的Vector
,将数据写入Vector
,再通过std::ptr::copy
到int_ptr
中,示例如下:
// Rust
use std::ptr;
#[no_mangle]
pub extern "C" fn write_to_c_buffers(n: usize, buffers: *mut i32) {
let mut tmp_buffers = Vec::with_capacity(n);
for index in 0..n {
tmp_buffers.push(index);
}
unsafe {
ptr::copy(tmp_buffers.as_ptr(), buffers, n);
}
}
上述的tmp_buffers
分配了一块与buffers
等长的新内存,显然没必要。使用std::slice
直接读写裸指针可实现前面C++式的做法,示例如下:
// Rust
use std::slice;
#[no_mangle]
pub extern "C" fn write_to_c_buffers(n: usize, buffers: *mut i32) {
unsafe {
let mut slice = slice::from_raw_parts_mut(buffers, n);
for index in 0..n {
slice[index] = index;
}
}
}
3.2 读指针
// C++
int summary(size_t count, int ptr*) {
int sum = 0;
for (int i = 0; i < count; ++i) {
sum += ptr[i];
}
return sum;
}
将ptr
传递到Rust进行求和,用slice可以直接操作,避免分配额外的内存,示例如下:
// Rust
use std::slice;
#[no_mangle]
pub extern "C" fn summary_for_c_buffers(n: usize, buffers: *const i32) {
unsafe {
let slice = slice::from_raw_parts(buffers, n);
let mut sum = 0;
for index in 0..n {
sum += slice[index];
}
sum
}
}
4. 判断指针是否为NULL/nullptr
假设存在const T* ptr1
和T* ptr2
,分别判断它们是否为空,C++和Rust实现如下所示。
// C++
if ((NULL == ptr1) || (nullptr == ptr2)) {}
// Rust
use std::ptr;
if ptr::null() == ptr1 || ptr::null_mut() == ptr2 {}
5. 返回nullptr/NULL
由前面可知,Rust提供C接口时返回nullptr或NULL实现如下
// Rust
#[no_mangle]
pub extern "C" fn init_engine() -> * const c_void {
// something goes wrong
std::ptr::null()
}
fn main() {
unsafe{
let engine = init_engine();
println!("{:?}", engine);
}
}
网友评论