Casting a align(4) u8 to [4]u8 or *[4]u8

const foo: u8 align(4) = 100;

now i want to know how to cast foo value into either
const z : [4]u8;
or
const z: *[4]u8;

align(4) sets the starting address of foo to be a multiple of 4 bytes.
Size of foo is one byte. You cannot cast one byte to an array of bytes.
You must decide which element of the z array receives the foo value and what happens to the other elements (e.g. nothing, they become zero).
Example:

const foo: u8 align(4) = 100;
const z: [4]u8 = {foo, 0, 0, 0};

or

var z: [4]u8 = std.mem.zeroes([4]u8);
z[0] = foo;
const pz: *[4]u8 = &z;
pz.*[0] = foo;
2 Likes

can you explain behaviour of align keyword

align sets the alignment of variables or functions. Pointers to variables or functions follow the specified alignment.

Alignment is a number of bytes that is power of 2. Address of aligned variables or functions are evenly divisible by the alignment.

It is a linker (and/or compiler) job to correctly align the variables and the functions so that they have the correct alignment.

For example u8 align(4) means that we store 8 bits/1 byte and the address modulo 4 must be zero (multiple of 32-bits starting from 0).

Pointers and slices can also have alignment, align can be used to set a pointer alignment.
There is no need to specify pointer alignment because it is derived from the type that the pointer points to.

For example:

var foo: u8 align(4) = undefined;
const bar: *align(4) u8 = &foo;

see also: Documentation - The Zig Programming Language
and: Documentation - The Zig Programming Language

1 Like

But we can cast single item pointer to multi-item pointer:

const std  = @import("std");

pub fn main() void {
    const a: u8 = 123;
    const p1: *const u8 = &a;
    const p2: [*]const u8 = @ptrCast(p1);

    var k: usize = 0;
    while (k < 4) : (k += 1) {
        std.debug.print("p2[{}] = {}\n", .{k, p2[k]});
    }
}

This prints the value of a (==123) and values of 3 bytes after a:

p2[0] = 123
p2[1] = 0
p2[2] = 37
p2[3] = 0

Of cource, this

  • does not make much sense, if any
  • has nothing to do with alignment

It means alignment doesn’t have any importance in casting

How 37 came

These are just some bytes “below” variable a on the stack.
I compiled my example in Debug mode.
In all the other modes (Safe, Fast, Small) it is more surprising:

p2[0] = 123
p2[1] = 123
p2[2] = 123
p2[3] = 123

It means alignment doesn’t have any importance in casting

Btw, what is “pointer alignment” exactly?
Is it alignment of a pointer itself?
I guess, natural alignment for pointers are 4/8 bytes, why should it depend on the alignment of the pointee?
Or is it a restriction on the content of a pointer?

Short answer: pointer alignment is the alignment of the underlying type.

Long answer; In the alignment section of the zig reference:

Each type has an alignment - a number of bytes such that, when a value of the type is loaded from or stored to memory, the memory address must be evenly divisible by this number.

In Zig, a pointer type has an alignment value. If the value is equal to the alignment of the underlying type, it can be omitted from the type

You can specify alignment on variables and functions. If you do this, then pointers to them get the specified alignment

1 Like

So, “alignment” is applicable to any variable, including pointers.
“Alignment value” is applicable to pointers only.

var a: f32 = 0.0;

Does var a have an alignment? Yes, it does.
Does content of var a have an alignment? Of course, no.

var p: *f32 = undefined;

Does var p (pointer) have an alignment? Yes, it is usual variable.
But this alignment is not necessarily equal to the alignment of f32, right?
Does content of a pointer has an “alignment”? Kinda yes, I called it “restriction”, Zig docs calls it “alignment value”. This means that pointer value can not be anything, it must be dividable by the size of what it points to.

For f32: pointer value (where it points to) should be multiple of 4, but address of the p may have different alignment, say, 8. Correct?

1 Like