@bitCast
@bitCast reinterprets the bits of one value as another type.
It does not do a normal conversion.
It does not change the bits.
It takes the same raw bit pattern and gives it a new type.
A Simple Example
Suppose you have a u32:
const x: u32 = 0x3f800000;Those 32 bits can also be interpreted as an f32.
const y: f32 = @bitCast(x);The value of y is 1.0, because the bit pattern 0x3f800000 is the IEEE 754 representation of 1.0 as a 32-bit float.
The integer value was not numerically converted.
This is not the same as:
const y: f32 = @floatFromInt(x);That would convert the number 1065353216 into a floating-point value.
@bitCast keeps the bits exactly the same.
Source and Destination Must Have the Same Size
@bitCast only works when the source type and destination type have the same size.
This is valid:
const x: u32 = 0x3f800000;
const y: f32 = @bitCast(x);Both u32 and f32 are 4 bytes.
This is invalid:
const x: u32 = 123;
const y: u64 = @bitCast(x);A u32 is 4 bytes. A u64 is 8 bytes. Zig rejects this because the bit counts do not match.
If you want a numeric conversion, use a numeric cast or conversion builtin, not @bitCast.
@bitCast Is About Representation
A value has two views:
meaning: what the value represents
bits: how the value is storedFor example:
const n: u32 = 65;The meaning is the number 65.
The bits are the binary representation of 65.
With normal conversion, Zig keeps the meaning.
With @bitCast, Zig keeps the bits.
That is the central difference.
Normal Conversion vs Bit Cast
Normal conversion:
const a: u8 = 65;
const b: u32 = a;The number is still 65. The destination type has more space, so the value is widened safely.
Bit cast:
const a: [4]u8 = .{ 65, 0, 0, 0 };
const b: u32 = @bitCast(a);Here, Zig takes the four bytes and treats them as a u32.
The result depends on byte order and layout rules.
For beginner code, remember this: @bitCast works at the storage level, not the ordinary arithmetic level.
A Complete Example
const std = @import("std");
pub fn main() void {
const bits: u32 = 0x3f800000;
const value: f32 = @bitCast(bits);
std.debug.print("{}\n", .{value});
}Output:
1e0The exact formatting may look different depending on how the float is printed, but the value is 1.0.
Bit Casting Structs
You can bit cast between types with the same size.
Example:
const Pair = extern struct {
a: u16,
b: u16,
};
const raw: u32 = 0x00020001;
const pair: Pair = @bitCast(raw);This treats the 32-bit integer as a struct containing two 16-bit fields.
The exact field values depend on endianness. On little-endian systems, the lower byte comes first in memory.
This is one reason you must be careful when using @bitCast for file formats or network protocols. External formats often define a specific byte order. Your CPU may use a different byte order.
Use extern or packed When Layout Matters
If you bit cast into a struct, the struct layout matters.
A normal Zig struct does not promise the same layout as a C struct or packed binary format.
For layout-sensitive code, use extern struct or packed struct when appropriate.
Example:
const Header = extern struct {
magic: u16,
version: u16,
};An extern struct follows C ABI layout rules.
For exact bit-level layout, use packed struct:
const Flags = packed struct {
read: bool,
write: bool,
execute: bool,
};Do not bit cast into ordinary structs when the byte layout must be stable across targets.
@bitCast Creates a New Value
@bitCast works on values.
It does not create another pointer to the same memory.
Example:
const x: u32 = 0x3f800000;
const y: f32 = @bitCast(x);y is a new value whose bits match x.
This is different from @ptrCast, which changes how a pointer views existing memory.
const p: *u32 = &x;
const q: *f32 = @ptrCast(p);Here, q points to the same memory as p, but with a different pointer type.
Use @bitCast when you want a value-level reinterpretation.
Use @ptrCast when you need pointer-level reinterpretation.
Common Use Cases
@bitCast appears in low-level code.
Common uses include:
floating-point bit inspection
binary protocols
file format parsing
hashing
serialization
emulators
compilers
graphics code
SIMD-related code
hardware-oriented codeFor normal application code, you rarely need it.
Most type changes should be normal conversions, not bit casts.
Example: Inspecting Float Bits
const std = @import("std");
pub fn main() void {
const value: f32 = 1.0;
const bits: u32 = @bitCast(value);
std.debug.print("0x{x}\n", .{bits});
}Possible output:
0x3f800000This is useful when you need to inspect the internal representation of a floating-point number.
Example: Reading Four Bytes as an Integer
const std = @import("std");
pub fn main() void {
const bytes = [4]u8{ 1, 0, 0, 0 };
const value: u32 = @bitCast(bytes);
std.debug.print("{}\n", .{value});
}On a little-endian target, this prints:
1But this is not portable as a file format parser unless the byte order is handled deliberately.
For external binary data, prefer explicit endian-aware functions from the standard library.
The clearer idea is:
File bytes have a defined byte order.
Your CPU has its own byte order.
Do not confuse the two.When Not to Use @bitCast
Do not use @bitCast for ordinary numeric conversion.
Wrong idea:
const x: u32 = 42;
const y: f32 = @bitCast(x);This does not produce 42.0.
It produces a floating-point value whose bits are the same as integer 42. That value is tiny and meaningless for normal arithmetic.
Use numeric conversion instead.
For integer to float:
const y: f32 = @floatFromInt(x);For float to integer:
const n: u32 = @intFromFloat(y);For integer size changes:
const small: u8 = @intCast(big);Compile-Time Checking
Zig checks that the source and destination sizes match.
Example:
const a: u16 = 10;
const b: u32 = @bitCast(a);This is rejected because 2 bytes cannot be bit cast into 4 bytes.
This check is valuable. It prevents many representation mistakes before the program runs.
How to Read @bitCast
When you see:
const b: B = @bitCast(a);read it as:
Create a B value using the same bits as a.Then ask:
Do A and B have the same size?
Is the destination type valid for these bits?
Does layout matter?
Does endianness matter?
Would a normal conversion be more correct?Most bugs with @bitCast come from using it when the programmer really wanted a normal conversion.
Key Idea
@bitCast reinterprets a value’s bits as another type of the same size.
It preserves representation, not meaning.
Use it for low-level representation work. Avoid it for ordinary conversions.