mohsentux
mohsentux

Reputation: 405

How do I pass arguments by reference when calling Rust from C++?

I am trying to do a very simple test to see how I can call Rust functions from C/C++.

My C++ code:

#include <iostream>
#include <cstdint>

extern "C" {

int32_t add_one(int32_t x);

} // extern "C"

using namespace std;

int main() {
    int32_t x = 14;
    cout << x << endl;
    cout << add_one(x) << endl;
    cout << x << endl;
}

My Rust code:

#[no_mangle]
pub extern "C" fn add_one(x: i32) -> i32 {
    x + 1
}

Compiled to a library, this gives a .dll and a .d file to compile against:

g++ main.c libc_rust.a -o output.exe

As I expect, this gives me 14 15 14.

How do I make my Rust function not return an integer but instead take x as a reference and increase the value of x by 1, giving the output 14 15 15?

If I write pub extern "C" fn add_one(x: i32) -> () using parenthesis, that means the return value is unit. I don't know what "unit" is exactly, but seems to do the job for void in this situation.

Upvotes: 0

Views: 1511

Answers (1)

Shepmaster
Shepmaster

Reputation: 432139

#[no_mangle]
// See note below
pub extern "C" fn add_one(x: &mut i32) {
    *x += 1;
}
#include <iostream>
#include <cstdint>

extern "C" {

void add_one(int32_t *x);

} // extern "C"

using namespace std;

int main() {
    int32_t x = 14;
    cout << x << endl;
    add_one(&x);
    cout << x << endl;
    cout << x << endl;
}

By using &mut in the function argument, we are requiring that the caller provides a valid reference. Among other things, that requires that:

  • It not be NULL
  • It be properly aligned
  • It doesn't alias any other value.

It's up to the caller of the function to ensure these conditions, otherwise it will cause undefined behavior.

See also:

Upvotes: 5

Related Questions