4 ms·
Memory layout in Zig with formulas
- raymondtana 8mo agoI've been learning Zig, and needed a refresher on memory layout (@sizeOf and @alignOf). Wrote this blog post to summarize what I think are the right ways to understand alignment and size for various data types in Zig, just through experimentation. Let me know any and all feedback!
- dnautics 8mo agoi could be wrong but i believe the zig compiler reserves the right to lay things out differently depending on compilation mode? especially debug. unless it's extern or packed, in which case the layout will be defined.
- rvrb 8mo ago`extern` and `packed` container types have well defined layouts. a regular `struct` is an "auto" layout - and the compiler can and will rearrange whenever it wants. if you need a well defined layout, use `extern`. if your struct makes sense to represent as an integer, use `packed`. I think it is often ill advisable to use `packed` otherwise. you can explore this yourself on the Type info returned from @TypeInfo(T): https://ziglang.org/documentation/master/std/#std.builtin.Type https://ziglang.org/documentation/master/std/#std.builtin.Ty... https://ziglang.org/documentation/master/std/#std.builtin.Type.Struct https://ziglang.org/documentation/master/std/#std.builtin.Ty... https://ziglang.org/documentation/master/std/#std.builtin.Type.ContainerLayout https://ziglang.org/documentation/master/std/#std.builtin.Ty...
- LexiMax 8mo agoTo wit: https://ziglang.org/documentation/master/#extern-struct https://ziglang.org/documentation/master/#extern-struct > An extern struct has in-memory layout matching the C ABI for the target. Zig is really good at speaking the C ABI of the target, but the upshot seems to be that it appears there is no stable Zig-native ABI. If I'm correct, I wonder if there are plans to settle on a stable ABI at some point in the future. I do know that in other languages the lack of a stable ABI is brought up as a downside, and although I've been burned by C++ ABI stability too many times to agree, I can understand why people would want one.
- Cloudef 8mo agoI doubt zig will have stable abi any time soon. It may have some sort of "zig extern" when it gets mature. But stable abi isnt very usful if no-one else can talk it. I have project that uses codegen to effectively implement zig like ABI on top of the C abi. Heres the kind of code it generates https://zigbin.io/6dba68 https://zigbin.io/6dba68 It can also generate javascript, heres doom running on browser: https://cloudef.pw/sorvi/#doom.wasm https://cloudef.pw/sorvi/#doom.wasm
- peesem 8mo agoAndrew Kelley has said relatively recently that there are no plans to introduce a Zig ABI: https://github.com/ziglang/zig/issues/3786#issuecomment-2646658356 https://github.com/ziglang/zig/issues/3786#issuecomment-2646...
- dnautics 8mo agoin practice, as long as you match the version and release mode, it's fine (though you are playing with fire). I pass raw pointers to zig structs/unions/etc from the zig compiler into a dynamically loaded .so file (via dlload) and as long as my .so file is compiled with the same compiler as the parent (both LLVM, in my case) it's peachy keen.
- Cloudef 8mo agoYou are still playing with fire as the data inside those pointers may be different even if they are the same type. Zig is free to optimize them in anyway it likes depending on the code that touches them (aka its free to assume they never leave the program).
- repiret 8mo ago> CPUs fetch data from memory in fixed-size blocks of so-many bytes, and performance degrades when data is misaligned. A memory bus supports memory transactions of various sizes, with the largest size supported being a function of how many data lines there are. The following two statements are true of every memory bus with which I'm familiar, and I probably every bus in popular use: (1) only power-of-two sizes are supported; (2) only aligned transactions are supported. Arm, x86, and RISC-V are relatively unique among the multitude of CPU architectures in that if they are asked to make an unaligned memory transaction, they will compose that transaction from multiple aligned transactions. Or maybe service it in cache and it never has to hit a memory bus. Most CPU architectures, including PPC, MIPS, Sparc, and ColdFire/68k, will raise an exception when asked to perform a misaligned memory transaction. The tradition of aligning data originated when in popular CPU architectures, if you couldn't assume that data was aligned, you would need to use many CPU instructions to simulate misalinged access in software. It continued in compilers for Arm and x86 because even though those CPUs could make multiple bus transactions in response to a single mis-aligned memory read, that takes time and so it was much slower. I don't know for sure, but I would expect that on modern x86 and high performance Arm, the performance penalty is quite small, if there's any at all.
- Joker_vD 8mo agoIt's small, but not unnoticeable... depending on the exact size of the workload and the amount of computation per element. In fact, for huge arrays it may be beneficial to have structs packed if that leads to less memory traffic. [0] https://jordivillar.com/blog/memory-alignment https://jordivillar.com/blog/memory-alignment [1] https://lemire.me/blog/2012/05/31/data-alignment-for-speed-myth-or-reality/ https://lemire.me/blog/2012/05/31/data-alignment-for-speed-m... [2] https://lemire.me/blog/2025/07/14/dot-product-on-misaligned-data/ https://lemire.me/blog/2025/07/14/dot-product-on-misaligned-...
- bk496 8mo agouseful!
- thechao 8mo agoI know this is a bit cursed; but, I always wanted a bitfield-on-steroids construct: struct Dang : bits 64 // 64 bits wide, int total { foo : bits 5 @ 0; // 5 bits wide at bit offset 0 bar : bits 5 @ 0; baz : bits 16 @ 4; // 16 bits wide at bit offset 4 tom : bits 11 @ 32; };
- _bohm 8mo agoYou can kinda do this with Zig’s packed structs and arbitrary-width integers
- deleted 8mo ago[deleted]
- sestep 8mo agoI think you can do this with Virgil, but I'm having trouble finding the exact doc page at the moment: https://github.com/titzer/virgil https://github.com/titzer/virgil
- titzer 8mo agoThe description is in the paper, but not all of it is implemented. https://arxiv.org/abs/2410.11094 https://arxiv.org/abs/2410.11094 Bradley implemented a prototype of the packing solver, but it doesn't do the full generality of what is proposed in the paper.
- Lvl999Noob 8mo agoAre you saying you want foo and bar to completely overlap? And baz and foo / bar to partially overlap? And have lots of unused bits in there too?
- metaltyphoon 8mo agoC# can do this with structs. Its kind of very nice to unpack wire data.
- ivanjermakov 8mo agoI also had to learn struct alignment the hard way working on WebGPU path tracer and struggling to understand why struct fields not aligning (ironically).
- andsoitis 8mo agoMemory layout of a data structure in various programming languages: https://rosettacode.org/wiki/Memory_layout_of_a_data_structure https://rosettacode.org/wiki/Memory_layout_of_a_data_structu...
- travisgriggs 8mo ago> I imagine just about any computer science major would have learned the rules of memory layout according to some kind of C-like compiler. I have worked with a number of fresh grads over the last ten years. I can think of one who may have had a good handle on this. At best the rest range from “vague memory recall about this” to a blank stare. On the flip hand, it’s something someone can pick up pretty quickly if motivated.