C++與Rust操作裸指標的比較

熊皮皮發表於2018-11-13

文件列表見:Rust 移動端跨平臺複雜圖形渲染專案開發系列總結(目錄)

判斷指標是否為NULL/nullptr

假設存在const T* ptr1T* ptr2,分別判斷它們是否為空,C++和Rust實現如下所示。

if ((NULL == ptr1) || (nullptr == ptr2)) {
  // do something
}
複製程式碼
use std::ptr;

if ptr::null() == ptr1 || ptr::null_mut() == ptr2 {
    // do something
}
複製程式碼

返回nullptr/NULL

由前面可知,Rust提供C介面時返回nullptr或NULL的實現如下

#[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);
    }
}
複製程式碼

使用slice直接讀寫指標內容

寫指標

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中,示例如下:

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++式的做法,示例如下:

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; 
        }
    }
}
複製程式碼

進一步,可使用Rust類似C#的foreach進行迴圈,同時縮小unsafe程式碼塊的影響空間。讀指標也可用這個方案。

use std::slice;

#[no_mangle]
pub extern "C" fn write_to_c_buffers(n: usize, buffers: *mut i32) {
  let mut buffers = unsafe { slice::from_raw_parts_mut(buffers, n) };
  for slice in buffers {
    *slice = //do something; 
  }  
}
複製程式碼

讀指標

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可以直接操作,避免分配額外的記憶體,示例如下:

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
    }
}
複製程式碼

相關文章