How to implement the C flexible array member pattern in Rust?
Asked Answered
V

1

15

I would like to implement this C code which uses a flexible array member (sometimes called the struct hack) in Rust:

struct test {
  int key;
  int dataSize;
  int data[];
};
struct test* t = malloc(sizeof(struct test) + sizeOfData)

The empty array at the end of structure allows you to allocate your meta fields and data all at once. Unfortunately, I can't figure out how to do such thing in Rust.

Vetavetch answered 23/6, 2018 at 22:47 Comment(3)
users.rust-lang.org/t/…Endow
I think you could achieve this on nightly with the allocator API and a decent amount of unsafe. But I'm not familiar enough with how it works in C. What if the alignment of the data array is bigger than the size of the header -- are padding bytes counted in the sizeof, or do we just rely on malloc allocating more than necessary to satisfy the maximum possible alignment?Mirisola
@MatthieuM. Probably my fault because you can't avoid padding bytes like I said, both sizeof and offsetof must produce the same size for FAM.Endow
B
2

The Rust equivalent of this struct would use a slice:

struct test {
  key: i32,
  dataSize: i32,
  data: [i32],
}

however, these types are not really convenient to use at the moment as there is no safe way to construct them.

A more practical way to do this is to use a generic:

struct test<T: ?Sized> {
  key: i32,
  dataSize: i32,
  data: T,
}

and then to make sure that you only use test when T is an array or a slice (which you could only create through coercion).

See also:

Benedic answered 1/9, 2019 at 21:36 Comment(5)
no it's wrong, slice contains their len, FAM doesn't. There is no equivalent of FAM in Rust ATM.Endow
@Endow [T] does not contain the length. You are talking about &[T] which is a fat pointer to a slice: that contains the length. But not the unsized [T] itself.Fulvous
@JL2210 A fat pointer is a pointer + some extra data, for example &[T] is a fat pointer, as it contains the address to the first element + the size, and &dyn Trait is a fat pointer as it contains a pointer to the data + a pointer to the vtable.Benedic
@LukasKalbertodt but this would not make sense in Rust, [T] need to know its size somehow, if you need unsafe this would not be Rust for me. Say [T] is the equivalent of FAM is wrong for me, at least for now.Endow
Hoi! Could this be the correct solution to all of this? At least pointers to structs with an extern type as last field are not fat pointers.Fulvous

© 2022 - 2024 — McMap. All rights reserved.