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] }
   |              ^^^^^^^^
1
  • 2
    Aside: the Rust equivalent of C's int is not i32; it's c_int in the libc crate. Commented Feb 7, 2018 at 9:54

2 Answers 2

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] }
}
Sign up to request clarification or add additional context in comments.

1 Comment

This was exactly what I wanted. Worked perfectly
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));
    }
}

2 Comments

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 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.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.