New Rustacean e029: I'm Out to C

#1

Using Rust’s Foreign Function Interface (FFI) with C! (Part one of several about FFI!)

3 Likes
#2

Great episode, as always! :heart:

Just a small note: when you talk about the fact that C can do whatever it wants, it is not true that ‘point’ can be changed… at least not the value we passed to the FFI function. In other words, C does not have the concept of references (like C++), therefore ‘point’ is a Point * by value. The function can change it, but this will not any visible behaviour from the caller point of view. As a consequence, Point * const in a function declaration is useful for the maintainer of the function to avoid erroneous changes to the pointer (not the Point itself) , nothing more.

#3

Oh, excellent correction. Clearly my C is rusty (no pun intended!). Thank you!

1 Like
#4

Here are examples of writing to the 4 permutations of constness of pointer vs referent,
annotated with compile-time errors:

In C:

#include <stdio.h>


/*
    No errors
*/
void func0(int* foo){
    *foo=10;
    foo=NULL;
}


/*
    foo.c: In function ‘func1’:
    foo.c:12:8: error: assignment of read-only parameter ‘foo’
         foo=NULL;
            ^
*/
void func1(int*const foo){
    *foo=10;
    foo=NULL;
}

/*
    foo.c: In function ‘func2’:
    foo.c:22:9: error: assignment of read-only location ‘*foo’
         *foo=10;
             ^
*/
void func2(const int* foo){
    *foo=10;
    foo=NULL;
}


/*
    foo.c: In function ‘func3’:
    foo.c:37:9: error: assignment of read-only location ‘*foo’
         *foo=10;
             ^
    foo.c:38:8: error: assignment of read-only parameter ‘foo’
         foo=NULL;
            ^
*/
void func3(const int*const foo){
    *foo=10;
    foo=NULL;
}



int main(){
    return 0;
}

In Rust:

use std::ptr;

/*
    No errors
*/
fn func0(mut foo:*mut i32){
    unsafe{
        *foo=10;
        foo=ptr::null_mut();
    }
}

/*
    error[E0384]: cannot assign to immutable argument `foo`
     --> src/lib.rs:7:9
      |
    4 | fn func1(foo:*mut i32){
      |          --- help: make this binding mutable: `mut foo`
    ...
    7 |         foo=ptr::null_mut();
      |         ^^^^^^^^^^^^^^^^^^^ cannot assign to immutable argument
*/
fn func1(foo:*mut i32){
    unsafe{
        *foo=10;
        foo=ptr::null_mut();
    }
}

/*
    error[E0594]: cannot assign to `*foo` which is behind a `*const` pointer
      --> src/lib.rs:13:9
       |
    11 | fn func2(mut foo:*const i32){
       |                  ---------- help: consider changing this to be a mutable pointer: `*mut i32`
    12 |     unsafe{
    13 |         *foo=10;
       |         ^^^^^^^ `foo` is a `*const` pointer, so the data it refers to cannot be written

*/
fn func2(mut foo:*const i32){
    unsafe{
        *foo=10;
        foo=ptr::null();
    }
}


/*

    error[E0594]: cannot assign to `*foo` which is behind a `*const` pointer
      --> src/lib.rs:20:9
       |
    18 | fn func3(foo:*const i32){
       |              ---------- help: consider changing this to be a mutable pointer: `*mut i32`
    19 |     unsafe{
    20 |         *foo=10;
       |         ^^^^^^^ `foo` is a `*const` pointer, so the data it refers to cannot be written

    error[E0384]: cannot assign to immutable argument `foo`
      --> src/lib.rs:21:9
       |
    18 | fn func3(foo:*const i32){
       |          --- help: make this binding mutable: `mut foo`
    ...
    21 |         foo=ptr::null();
       |         ^^^^^^^^^^^^^^^ cannot assign to immutable argument

*/
fn func3(foo:*const i32){
    unsafe{
        *foo=10;
        foo=ptr::null();
    }
}
2 Likes