References

3 Posts

Pointers, References, and Raw Pointers

6 minute

C uses T * everywhere. It can mean many different things:

void print_config(const struct Config *cfg);
void reset_config(struct Config *cfg);
int parse_packet(const uint8_t *data, size_t len, struct Packet *out);
void driver_write(void *addr, uint32_t value);

These all look like pointers, but the meanings differ:

  • read-only access to an object
  • mutation of a caller-provided object
  • pointer plus length for a buffer
  • output parameter
  • nullable pointer
  • hardware address or FFI-provided address

Rust does not put all of these into one pointer concept. Start with this table:

const T *              -> &T / Option<&T>
T *                    -> &mut T / Option<&mut T>
const T * + len        -> &[T]
T * + capacity         -> &mut [T]
out parameter          -> return value / &mut T / &mut [T]
void *                 -> generic, trait, raw pointer, or FFI context
real address / FFI ptr -> *const T / *mut T

The first layer is the split itself: ordinary library APIs should prefer references and slices, while raw pointers should stay close to FFI, hardware addresses, and low-level wrappers.

Read More

Lifetimes: References Cannot Outlive Data

5 minute

When C developers first see lifetimes, it is easy to think they are annotations for “how long an object lives.”

That is not quite right.

Rust lifetimes are not runtime timers, and they are not manual descriptions of real object lifetime. They are static constraints the compiler uses to check reference relationships: a reference cannot outlive the data it points to.

C has the same problem. It is just checked by humans.

Read More

Borrowing: References Are Not Plain Pointers

5 minute

The previous article covered ownership: who owns, who frees.

Most functions do not want to take over a resource. They only want to inspect data temporarily, or mutate it temporarily. In C, this usually means passing a pointer:

void inspect(const uint8_t *buf, size_t len);
void update(uint8_t *buf, size_t len);

In Rust, this is borrowing:

fn inspect(buf: &[u8]) {}
fn update(buf: &mut [u8]) {}

Borrowing is not just “Rust pointer syntax.” It is access permission: temporarily read or write without taking ownership.

This article covers the first engineering meaning of &T and &mut T, without expanding lifetime annotations yet.

Read More