• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1{{#title *mut T, *const T — Rust ♡ C++}}
2# *mut T, *const T
3
4Generally you should use references (`&mut T`, `&T`) or [std::unique_ptr\<T\>]
5where possible over raw pointers, but raw pointers are available too as an
6unsafe fallback option.
7
8[std::unique_ptr\<T\>]: uniqueptr.md
9
10### Restrictions:
11
12Extern functions and function pointers taking a raw pointer as an argument must
13be declared `unsafe fn` i.e. unsafe to call. The same does not apply to
14functions which only *return* a raw pointer, though presumably doing anything
15useful with the returned pointer is going to involve unsafe code elsewhere
16anyway.
17
18## Example
19
20This example illustrates making a Rust call to a canonical C-style `main`
21signature involving `char *argv[]`.
22
23```cpp
24// include/args.h
25
26#pragma once
27
28void parseArgs(int argc, char *argv[]);
29```
30
31```cpp
32// src/args.cc
33
34#include "example/include/args.h"
35#include <iostream>
36
37void parseArgs(int argc, char *argv[]) {
38  std::cout << argc << std::endl;
39  for (int i = 0; i < argc; i++) {
40    std::cout << '"' << argv[i] << '"' << std::endl;
41  }
42}
43```
44
45```rust,noplayground
46// src/main.rs
47
48use std::env;
49use std::ffi::CString;
50use std::os::raw::c_char;
51use std::os::unix::ffi::OsStrExt;
52use std::ptr;
53
54#[cxx::bridge]
55mod ffi {
56    extern "C++" {
57        include!("example/include/args.h");
58
59        unsafe fn parseArgs(argc: i32, argv: *mut *mut c_char);
60    }
61}
62
63fn main() {
64    // Convert from OsString to nul-terminated CString, truncating each argument
65    // at the first inner nul byte if present.
66    let args: Vec<CString> = env::args_os()
67        .map(|os_str| {
68            let bytes = os_str.as_bytes();
69            CString::new(bytes).unwrap_or_else(|nul_error| {
70                let nul_position = nul_error.nul_position();
71                let mut bytes = nul_error.into_vec();
72                bytes.truncate(nul_position);
73                CString::new(bytes).unwrap()
74            })
75        })
76        .collect();
77
78    // Convert from Vec<CString> of owned strings to Vec<*mut c_char> of
79    // borrowed string pointers.
80    //
81    // Once extern type stabilizes (https://github.com/rust-lang/rust/issues/43467)
82    // and https://internals.rust-lang.org/t/pre-rfc-make-cstr-a-thin-pointer/6258
83    // is implemented, and CStr pointers become thin, we can sidestep this step
84    // by accumulating the args as Vec<Box<CStr>> up front, then simply casting
85    // from *mut [Box<CStr>] to *mut [*mut CStr] to *mut *mut c_char.
86    let argc = args.len();
87    let mut argv: Vec<*mut c_char> = Vec::with_capacity(argc + 1);
88    for arg in &args {
89        argv.push(arg.as_ptr() as *mut c_char);
90    }
91    argv.push(ptr::null_mut()); // Nul terminator.
92
93    unsafe {
94        ffi::parseArgs(argc as i32, argv.as_mut_ptr());
95    }
96
97    // The CStrings go out of scope here. C function must not have held on to
98    // the pointers beyond this point.
99}
100```
101