In order to ease the burden of processing examples at On type choices and "idiomatic" way to add a negative number to usize, I decided to implement a simple function that would inspect (print) the content of integers bit by bit. As a working solution, I wrote the following:
const std = @import("std");
pub fn dumpBits(comptime T: anytype, comptime value: T) ![]const u8 {
if (@typeInfo(T) != .Int) return error.ValueShouldBeAnInteger;
const T_info = @typeInfo(T);
const Uint = std.meta.Int(.unsigned, T_info.Int.bits);
comptime var mask: Uint = 1 << (T_info.Int.bits - 1);
const casted: Uint = @bitCast(value);
comptime var out: []const u8 = "";
inline while (mask != 0) : (mask /= 2) {
const bit = if (casted & mask == 0) "0" else "1";
out = out ++ bit;
}
return out;
}
pub fn main() !void {
std.log.debug("max usize: {s}", .{try intToBits(u8, std.math.maxInt(u8))});
std.log.debug(" -42: {s}", .{try intToBits(i8, -42)});
}
It gives:
debug: max usize: 11111111
debug: -42: 11010110
Feels right. However, I felt like the solution could be a bit more simple and generic, for example, the one that would allow me to print bits of a struct. So I made a sketch that doesn’t work:
pub fn dumpBits(comptime T: anytype, comptime value: T) ![]const u8 {
comptime var out: []const u8 = "";
const len = @bitSizeOf(T);
const casted: [len]u1 = @bitCast(value); // error because [len]u1 with padding takes ~8x more bits
inline for (casted) |bit| {
out = out ++ if (bit == 1) "1" else "0";
}
return out;
}
I really like this solution, and would be nice if it worked, because we simply cast something into array of bits and print them one by one. However, running this function:
pub fn main() !void {
const Struct = packed struct {
f1: u8,
f2: i8,
};
const data = Struct{ .f1 = 1, .f2 = -1 };
std.log.debug("{s}", .{try dumpBits(Struct, data)});
}
Gives:
howtos/q_bitFiddling.zig:23:29: error: @bitCast size mismatch: destination type '[16]u1' has 121 bits but source type 'q_bitFiddling.main.Struct' has 16 bits
const casted: [len]u1 = @bitCast(value); // error because [len]u1 with padding takes ~8x more bits
^~~~~~~~~~~~~~~
At this point, I’m unsure about how to handle paddings, bit casting like this, and potential concerns with endianness (like when do I need to think about them).