37

Is it possible to call C or C++ functions within Rust? If so, how is this done?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
user2971895
  • 391
  • 1
  • 3
  • 4

3 Answers3

25

Rust doesn't support this directly, C++ function symbol mangling is implementation defined, so it will need a lot of support from Rust to handle this feature. It's not impossible but it's probably not going to happen.

However, Rust claims to support the C language. This is clearly more easy to support, as it "only" needs to support the function calls of C. This is implementation-defined behavior too, but this doesn't change a lot and people agree to work together to share the same convention so you will not have a problem to use C as intermediary on common platform.

So, to call C++ from Rust, you must pass by C.

To call C from Rust, the docs show this example:

extern "C" {
    fn abs(input: i32) -> i32;
}

fn main() {
    unsafe {
        println!("Absolute value of -3 according to C: {}", abs(-3));
    }
}

To call C++ from C, a C++ function must be defined like this:

// This C++ function can be called from C code
extern "C" void handler(int) {
    std::cout << "Callback invoked\n"; // It can use C++
}

To transmute this example to our example in Rust, that gives:

#include <cstdlib>
#include <cinttypes>

extern "C" std::int32_t abs(std::int32_t n) {
    return std::abs(static_cast<std::intmax_t>(n));
}
kenorb
  • 155,785
  • 88
  • 678
  • 743
Stargateur
  • 24,473
  • 8
  • 65
  • 91
  • `// It can use C++` - just to be sure - it can't accept C++ types (such as `std::string`), nor return them, right? – Marc.2377 Nov 29 '19 at 17:30
  • @Marc.2377 yes and no, you can't directly "share" c++ type but you can give to the c part a `void *` C can't use it but can give it back to c++ part, and then c++ can cast it to the real type. – Stargateur Nov 30 '19 at 00:31
  • @Stargateur how do you get that `void *` from the Rust object? You might be able to get a `char*`, but C++ and Rust strings almost certainly have an compatible layout – OrangeDog Feb 04 '22 at 11:17
  • 1
    @OrangeDog the std::string in c++ and string in rust are completely different and don't work together. You need to either create a struct in rust to fake the memory layout of a c++ string and manipulate it through the dummy struct [or vice versa] (not recommended possibly compiler dependent) better work with char* which c++ and rust can convert into strings. But keep in mind rust strings are not \0 terminated. – RedCrafter LP Aug 08 '22 at 21:30
13

Rust can link to/call C functions via its FFI, but not C++ functions.

While I don't know why you can't call C++ functions, it is probably because C++ functions are complicated.

Michael Rawson
  • 1,905
  • 1
  • 15
  • 25
  • 5
    You can just define C linkage on any C++ function, making it available from C and thus also Rust. ```extern "C"``` is your friend here. – Jan Henke Sep 08 '15 at 11:57
2

If you wish to call C functions from libc there is a rust crate that allows writing C like code directly in rust, some of it requires unsafe blocks.

Below is an example of seting the nofile system limit. Instructions for this code are in man 2 setrlimit, i.e. the code maps almost directly from C to rust.

use libc::rlimit;
use libc::setrlimit;
use libc::RLIMIT_NOFILE;

/// Set system limits on number of "open files"
pub fn increase_rlimit_nofile(limit: u64) -> i32 {
    let lim = rlimit {
        rlim_cur: limit,
        rlim_max: limit
    };
    unsafe {
        let rv: i32 = setrlimit(RLIMIT_NOFILE, &lim);
        return rv;
    }
}
teknopaul
  • 6,505
  • 2
  • 30
  • 24