Size of type WITHOUT alignment padding

I'm writing some code which allocates a series of items into a contiguous region of memory, all of different types and sizes, something like: [val1: u32, val2: u8, etc].

Currently, the code looks something like this pseduocode:

block: *mut u8;
offset: isize;

for some_type in my_types {
    offset = round_up_to(offset, std::mem::align_of<some_type>());
    obj_ptr = block.offset(offset);

    // pointless padding space here!!!
    offset + std::mem::size_of::<some_type>();
}

My issue is that size_of::() not only returns the size of the type, but also padding to properly align what would be another of the same type afterwards in memory. I don't want to do that - I already manage the alignment myself, and don't want to waste space on pointless padding. For example, If I have a struct which requires 4 bytes of padding, followed by a struct which only requires 4 bytes of alignment, I want to start the next struct immediately instead of having 4 bytes of padding.

Unfortunately, code like:

#[attribute(packed)]
struct get_raw_size_of<T> {
    single_elem: T,
}

does not work, as the padding of single_elem is included anyways in the packed struct. Packing the original structs is also out of the question for me.

Is there a way to do this in stable rust?

1 Like

If you don't pack the original, then any writes to that struct may also clobber the padding area. I suspect that your intended use of that padding would be Undefined Behavior.

4 Likes

Looking at the compiler, it appears that this information is not exposed from the compiler.

@cuviper you're probably correct, the compiler may well write to this padding for any purpose if it deems it an optimization (using a 16-byte write over a series of smaller ones), which is unfortunate. This isn't currently done, but I can't find anything about whether it's allowed.

A representation without padding at the end would be difficult for a whole slew of reasons, but it would be useful to access that information and tell the compiler not to use that padding.

1 Like

It actually coalesces writes into one if you add one more field! Perhaps the cost of unaligned store is greater than cost of two writes, but smaller than three.

4 Likes

This seems roughly the same as what Separate size and stride for types · Issue #1397 · rust-lang/rfcs · GitHub wants/proposes.

3 Likes

I faced the need for such a function too when implementing a generic as. num_traits library did it via 13^2=169 implementations populated with macros.