美文网首页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