18

I might not have described my question title properly, please edit it if needed.

I'm trying to crate a Rust interface to LXC library, which is written in C.

I have successfully called simple functions like lxc_get_version or lxc_container_new but I cannot get access to functions described in struct lxc_container block.

Here is an part of my code:

#[link(name = "lxc")]
extern {
    // LXC part
    fn lxc_get_version() -> *const c_char;
    fn lxc_container_new(name: *const c_char, configpath: *const c_char) -> LxcContainer;

    // LXC container parts
    fn is_defined(container: &LxcContainer) -> bool; 
}

And here is an error:

note: test.o: In function `LxcContainer::is_defined::heb2f16a250ac7940Vba':
test.0.rs:(.text._ZN12LxcContainer10is_defined20heb2f16a250ac7940VbaE+0x3e): undefined reference to `is_defined'

EDIT: I have managed that functions inside C structs is called function pointers. I've tried to google something like "Rust C function pointer", but without luck.

1 Answer 1

26

When you see something like this (in C):

struct S {
    void (*f)(int, long)
}

it means that struct S contains a field called f which is a pointer to a function. It does not mean that the library itself exposes a function called f. For example, this is valid:

void some_function_1(int x, long y) { ... }

void some_function_2(int a, long b) { ... }

int main() {
    struct S s1; s1.f = some_function_1;
    struct S s2; s2.f = some_function_2;
}

Here struct instance s1 contains a pointer to some_function_1, and s2 contains a pointer to some_function_2.

When you're writing FFI binding in Rust for some C library, you usually define Rust counterparts for C structures. Some tools like rust-bindgen can even do this automatically. In your case you will have to write something like this:

#[repr(C)]
struct LxcContainer {
    name: *mut c_char,
    configfile: *mut c_char,
    // ...
    numthreads: c_int,
    // ...
    is_defined_f: extern fn(c: *mut LxcContainer) -> bool,
    state_f: extern fn(c: *mut LxcContainer) -> *const c_char,
    // ...
}

That is, weird-looking C function pointer types correspond to extern fn function pointer types in Rust. You could also write extern "C" fn(...) -> ..., but "C" qualifier is default so it is not required.

You will have to write something like this to call these functions:

impl LxcContainer {
    fn is_defined_f(&mut self) -> bool {
        unsafe {
            (self.is_defined_f)(self as *mut LxcContainer)
        }
    }
}

You need to cast a reference to a raw pointer and you also need to wrap self.is_defined_f in parentheses in order to disambiguate between method call and field access.

You can find more on FFI in Rust here. Function pointers are explained very briefly there, though.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for answer, I can now get access to function pointers. I have wrote a struct for C representation and a wrapper for Rust representation around it. Unfortunately I cannot make a call to is_defined because I cannot pass LxcContainer struct to function as *LxcContainer. Dereference error occurs. Could you please add some example of function pointer calling into your answer? Thank you.
@bbrodriges, sorry for the late reply, but I have updated my answer with an example of how to call functions stored in struct fields.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.