Are there always 2 free bits guarenteed in a pointer value of type with align(4) attributed?

(deleted bad demo code)

The answer is yes, since align(4) means (value % 4) == 0.

But note that the data type must have align(4)!
The pointers align(4) is there to ensure that you don’t put an address to misaligned data.

See the documentation about alignment:

1 Like

Are there always 2 free bits guarenteed in a pointer value of type with align(4) attributed?


What do you mean by 8 free bits? I think you mean 3 free bits?

@alignOf(comptime T: type) comptime_int

This function returns the number of bytes that this type should be aligned to for the current target to match the C ABI. When the child type of a pointer has this alignment, the alignment can be omitted from the type.

You have got 8 different addresses that could be masked to become the same pointer, however these addresses differ in the 3 least significant bits (not 8 bits).

2^3 bits = 8 possibilities

The 3 least significant bits are able to describe 8 different addresses, so if you write code where you set the 3 lowest bits to zero before dereferencing and you use pointers that have align(8) then you have 3 free bits, allowing you to use those bits to switch between 8 different types of pointers.

1 Like

Sorry, the conclusion I made from the demo code is wrong.
It should be unrelated to the topic.
I just deleted the code from the first comment.

But it looks the compiler never makes use of this fact to save some memory.
The following code always prints 8, 16, with any build mode.

const std = @import("std");

const T1 = struct {
	x: *align(4) u8,

const T2 = struct {
	x: *align(4) u8,
	a: bool,

pub fn main() !void {
    std.debug.print("{}, {}\n", .{@sizeOf(T1), @sizeOf(T2)}); // 8, 16

Should Zig programmer make use of this fact by themselves to same some memory?

I would only do optimizations like this, if you have measured that this improves memory usage and performance significantly.
But generally if you think that you need this optimization then you should probably look into different solution instead, like for example using as u16 or u32 as an index into an array instead of a native pointer. Or maybe you can use data oriented design, storing the bool in a bitset and the pointer in a different array.

1 Like

In different CPU architectures misaligned pointers are slower when accessing memory and in some cases it is a simple crash.
It is possible to use the extra pointer bits, when not accessing memory, to encode information. This is typically done by interpreters to encode integers and other values when the low bits are not zeros.
Zig allows to use the packed struct which really packs the various bit together.


To add to this, taking advantage of pointer alignment in packed structs is currently an open proposal: Proposal: do not include guaranteed-zero bits in packed representation of pointers · Issue #17474 · ziglang/zig · GitHub There are still some subtle details which would need to be worked out, but this would definitely be handy in working with the “tagged pointer” pattern you mentioned.