美文网首页Rust语言vulkan
C/C++转Rust的项目实践总结 1-5

C/C++转Rust的项目实践总结 1-5

作者: 熊皮皮 | 来源:发表于2018-10-14 01:09 被阅读137次

目录:

  • 导入外部符号
  • 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::copyint_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* ptr1T* 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);
    }
}

相关文章

网友评论

    本文标题:C/C++转Rust的项目实践总结 1-5

    本文链接:https://www.haomeiwen.com/subject/cmtfaftx.html