Data formatting in Zig
The program demonstrates various advanced string formatting capabilities provided by the Standard Library std.fmt module.
const std = @import("std");
const User = struct {
name: []const u8,
id: u32,
};
pub fn main(init: std.process.Init) !void {
const io = init.io;
const allocator = std.heap.page_allocator;
const stdout = std.Io.File.stdout();
std.debug.print("Debug: Program started.\n", .{});
const number = 255;
const msg_nums = try std.fmt.allocPrint(
allocator,
"Decimal: {d}, Hex: {x}, Binary: {b}, Octal: {o}\n",
.{ number, number, number, number },
);
defer allocator.free(msg_nums);
try stdout.writeStreamingAll(io, msg_nums);
const pi = 3.14159;
const msg_float = try std.fmt.allocPrint(
allocator,
"Pi (2 decimals): {d:.2} | Padded: {d: >10.2}\n",
.{ pi, pi },
);
defer allocator.free(msg_float);
try stdout.writeStreamingAll(io, msg_float);
const user = User{ .name = "Alice", .id = 101 };
const numbers = [_]u8{ 1, 2, 3 };
const msg_struct = try std.fmt.allocPrint(
allocator,
"User: {any}, Array: {any}\n",
.{ user, numbers },
);
defer allocator.free(msg_struct);
try stdout.writeStreamingAll(io, msg_struct);
var buffer: [64]u8 = undefined;
const slice = try std.fmt.bufPrint(
&buffer,
"Stack buffer: {s}-{d}",
.{ "Data", 42 },
);
try stdout.writeStreamingAll(io, slice);
try stdout.writeStreamingAll(io, "\n");
}
The code starts by importing the standard library and defining a simple User struct that holds a name as a string slice and an id as a u32. In the main function, the program initializes I/O handling, uses the page allocator for memory management (noted as a convenience for this example), and gets a handle to standard output. A debug message is printed first to indicate the program has started.
The code then shows numeric formatting for the integer 255. Using std.fmt.allocPrint(), it creates a formatted string displaying the number in decimal ({d}), hexadecimal ({x}), binary ({b}), and octal ({o}) formats. This dynamically allocates memory on the heap, writes the result to stdout using streaming output, and safely frees the memory afterward with defer.
Next, the program illustrates floating-point formatting with the value of π (3.14159). It formats the number to two decimal places and also demonstrates padding by right-aligning it within a 10-character field using the specifier {d: >10.2}. This again uses heap allocation via allocPrint followed by proper cleanup.
The example continues by formatting more complex types: a User struct instance (“Alice” with id 101) and a fixed-size array of bytes [1, 2, 3]. The {any} format specifier is used to recursively format these structures, producing readable output that includes the struct fields and array contents.
Finally, to avoid any heap allocation, the program uses a fixed-size stack buffer of 64 bytes with std.fmt.bufPrint() to format a simple message combining a string and an integer. The resulting slice is written directly to standard output, followed by a newline.
Save it as stdFmt.zig and execute it:
$ zig version
0.16.0
$ zig run stdFmt.zig
Debug: Program started.
Decimal: 255, Hex: ff, Binary: 11111111, Octal: 377
Pi (2 decimals): 3.14 | Padded: 3.14
User: .{ .name = { 65, 108, 105, 99, 101 }, .id = 101 }, Array: { 1, 2, 3 }
Stack buffer: Data-42
Happy coding in Zig!