0

I don't code in C much, but I am currently (attempting) to port a C project to Rust, and I don't understand what this does:

void example(const uint8_t *m, unsigned int r)
{
    m += r;
}

After a bit of Googling, I think that it's the same as m = m[r]. But if that is true, m and m[r] are two different data types (right...?). Trying to replicate this in Rust:

fn example(m: &mut [u8], r: u32) {
    m = m[r];
}

This gives the error mismatched types: expected `&mut [u8]`, found `u8, which makes sense. I either did the Rust part wrong, or I did not fully understand what the C part does. Can someone please explain where I went wrong?

  • 4
    It is the same as `m = &m[r]` (note the `&`). – Jmb Apr 21 '20 at 11:28
  • @Jmb But then you would be assigning **uint8_t to *uint8_t! How does that work? – MOHAMED ALSAN ALI Apr 21 '20 at 11:33
  • 2
    No you wouldn't. `m[r]` is of type `uint8_t`. So `&m[r]` is of type `uint8_t *` – kaylum Apr 21 '20 at 11:38
  • 2
    Rust is much strongly typed than C, and on a type level, Rust's slices don't really compare to C's pointers so this question doesn't make a whole lot of sense. – mcarton Apr 21 '20 at 11:45
  • 2
    Can't write an answer just now, but for your Rust code try `m = &mut m[r..]`. Also read [Can I reassign a mutable slice reference to a sub-slice of itself?](https://stackoverflow.com/q/61223234/3650362) if that doesn't work out of the box. – trent Apr 21 '20 at 11:47
  • @trentcl That might seem to work. I can’t test it rn but I get the idea. – MOHAMED ALSAN ALI Apr 21 '20 at 11:51
  • code do nothing. – Stargateur Apr 21 '20 at 12:29
  • The C code is just a very verbose no-op. It is passed a pointer and an integer value, performs an addition, and then doesn't do anything with the result. The effect of calling `example` is the same as not calling `example`. – IInspectable Apr 21 '20 at 12:34

1 Answers1

2

Given a pointer m to some element in an array, say x, and an integer r, m += r adjusts m to point to the element that is r elements after x.

For example, if m points to a[3] and r is 5, then m += r changes m to point to a[8].

In the case where m is a uint8_t *, it must point to elements that are bytes, and advancing m by r elements advances the pointer by r bytes. In cases where m points to a larger type, such as when m is int *, advancing m by r elements advances the pointer by r*s bytes, where s is the number of bytes in each element.

In many C implementations, bytes in memory are simply numbered consecutively starting with 0 (although not all bytes may be mapped in a virtual address space), and a pointer is represented with the number of the byte it points to. In this case, to increment a pointer by n bytes, the C implementation simply adds n to its representation. In C implementations with more complicated memory models, the C implementation performs whatever manipulations are needed to produce a pointer to the proper place.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312