Search code examples
rustexternffi

How to use a C typedef struct and functions with that struct from Rust?


I have these C files and I want to use pair_add, add and PAIR from Rust.

adder.c

#include <stdlib.h>
#include "adder.h"

int pair_add(PAIR * ppair) {
    return ppair->x + ppair->y;
}

int add(int x, int y) {
    return x + y;
}

adder.h

typedef struct {
    int x;
    int y;
} PAIR;

int pair_add(PAIR * ppair);
int add(int, int);

I compile them using:

gcc -c adder.c
ar rc libadder.a adder.o  # Static link

The documentation does not detail how to integrate C typedef structs and the example is for functions which return and accept i32. Other online resources were also limited.

I attempted the following but could not add the PAIR typedef:

extern crate libc;

use libc::c_int;

#[link(name = "adder")]
extern "C" {
    // Define PAIR

    // int pair_add(PAIR * ppair);
    fn pair_add(input: Pair) -> c_int;

    // int add(int, int);
    fn add(input1: c_int) -> c_int;
}

fn main() {}

Solution

  • First:

    typedef struct {
        int x;
        int y;
    } PAIR;
    

    This declares an anonymous struct and this is not currently supported by Rust. There is a RFC that proposes to add anonymous types.

    Secondly, a typedef is just an alias and the name of the struct isn't important to be compatible. That means that you can simply do:

    extern crate libc;
    use libc::c_int;
    
    #[repr(C)]
    struct PAIR {
        x: c_int,
        y: c_int,
    }
    
    // optional "equivalent" of typedef
    type Pair = PAIR;
    
    extern "C" {
        fn pair_add(input: *mut Pair) -> c_int;
        // could be
        // fn pair_add(input: *mut PAIR) -> c_int;
    }
    

    You could easily ignore the typedef and just use PAIR as a name for this struct. You can even just write struct PAIR; to make it opaque.