0

I'm using Rust to test some C code:

lol.c

#include "lol.h"
int a[10]; //Assume lol.h has an extern declaration for a[10]

lib.rs

extern "C" {
    static a: *mut i32;
}

fn set_a(val: i32, index: usize) {
    assert!(index < 10);
    unsafe {
        a[index] = val;
    }
}

fn get_a(index: usize) {
    assert!(index < 10);
    unsafe { a[index] }
}

I used the cc crate to compile and link lol.o. How do I write the set_a and get_a functions? The compiler says:

error[E0608]: cannot index into a value of type `*mut i32`
 --> src/main.rs:8:9
  |
8 |         a[index] = val;
  |         ^^^^^^^^

error[E0608]: cannot index into a value of type `*mut i32`
  --> src/main.rs:14:14
   |
14 |     unsafe { a[index] }
   |              ^^^^^^^^
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
KDN
  • 485
  • 2
  • 7
  • 18
  • 2
    Aside: the Rust equivalent of C's `int` is **not** `i32`; it's `c_int` in the [`libc`](https://crates.io/crates/libc) crate. – DK. Feb 07 '18 at 09:54

2 Answers2

7

You could use the offset method to find a single element, or use std::slice::from_raw_parts_mut to create a slice from pointer and (possibly dynamic) length, or use static mut a: *mut [i32; 10] in the first place (use (*a)[index] to use it).

But: I'm pretty sure that int a[10]; from C doesn't export a location of a pointer to that array, it exports the location of the array (i.e the location of the first element), and extern in Rust expects a location to a value of the given type (i.e. it is implemented as a pointer on both sides) , so I'd try this:

extern "C" {
    static mut a: [i32; 10];
}

fn set_a(val: i32, index: usize) {
    unsafe {
        a[index] = val;
    }
}

fn get_a(index: usize) -> i32 {
    unsafe { a[index] }
}
Stefan
  • 5,304
  • 2
  • 25
  • 44
2

Use:

a.offset(x) as *mut i32

Like this:

extern crate libc;

use libc::malloc;
use std::mem::size_of;

unsafe fn zero(data: *mut u32, length: usize) {
    for i in 0..length - 1 {
        let ptr = data.offset(i as isize) as *mut u32;
        *ptr = 0;
    }
}

unsafe fn set(data: *mut u32, offset: usize, value: u32) {
    let ptr = data.offset(offset as isize) as *mut u32;
    *ptr = value;
}

unsafe fn get(data: *mut u32, offset: usize) -> u32 {
    let ptr = data.offset(offset as isize) as *mut u32;
    return *ptr;
}

unsafe fn alloc(length: usize) -> *mut u32 {
    let raw = malloc(length * size_of::<*mut u32>());
    return raw as *mut u32;
}

fn main() {
    unsafe {
        let data = alloc(10);
        zero(data, 10);

        println!("{:?}", get(data, 4));

        set(data, 4, 100);
        println!("{:?}", get(data, 4));
    }
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Doug
  • 32,844
  • 38
  • 166
  • 222
  • I have two questions? Is the usize to isize because C indexing is different from Rust? Also why did you have to malloc. The space is already allocated in C right? – KDN Feb 07 '18 at 16:54
  • 1
    @KDN malloc was just an example (the code above runs on play.rust-lang.org). Obviously in your situation there's no need to malloc. The usize thing is because it's legal in C (and meaningful sometimes) to use x[-1]; so offset() can take a -ve number. In this case it's not meaningful to allow -ve values, so I made it usize instead of isize, but it's arbitrary. Just use isize if you don't care. – Doug Feb 08 '18 at 00:38