Zig's default optimization removes my comptime array entirely (?)

Below is my Zig program built using plain zig build and below that is my program using zig build -Doptimize=ReleaseFast (and Safe or Small)

Heads up: Im new to Zig and a fairly green self-taught programmer. The tldr is that I am building a hexdump tool. I have a comptime function that creates an array of strings that contain a set of ansi colors between 0 and 256 that I would like to be available to me at runtime. I then use the current byte of the hexdump as the index of the array to retrieve the ansi colors for the corresponding byte. This outputs a colorful hexdump that I really like since I can tell at a glance that green to purple-ish text is ASCII or otherwise.

The problem I am running into is that when I build my executable with -Doptimize=ReleaseXYZ it optimizes out the color somewhere along the line.

Can someone explain why or how the color is optimized out here and would you recommend any approach to avoid this from happening or potentially a better way to solve this problem.

the code:

var ColorArray: [][]const u8 = undefined;
// const ColorArray = ComputeColor(); // cant be done

pub fn ComputeColor() [][]const u8 {
    var array: [256][]const u8 = undefined;

    inline for (0..256) |i| {
        var full: []const u8 = "";
        const lowVis: bool = (i == 0 or (i >= 16 and i <= 20) or (i >= 232 and i <= 242));

        const istr: []const u8 = std.fmt.comptimePrint("{d}", .{i});

        if (lowVis) {
            full = "\x1b[48;5;" ++ istr ++ "m" ++ "\x1b[1;37m\x1b[38;5;255m";
        } else {
            full = "\x1b[38;5;" ++ istr ++ "m";
        }

        array[i] = full;
    }

    return &array;
}

fn Colorize(clr: u8) []const u8 {
    return ColorArray[clr];
}

pub fn Hexxy2(fname: []const u8) !void {
    // -- abbreviated for brevity
    while (true) {
        const n = try r.read(&line);
        if (n == 0) {
            break;
        }

        // print offset and separator
        stdout.print("{s}{x:0>8}│{s} ", .{ GREY, counter, CLR }) catch |err| {
            std.debug.print("{any}", .{@errorName(err)});
        };

        var i: usize = 0;
        var line_count: usize = 0;

        while (i < n) : (i += 1) {
            const clr = Colorize(line[i]);
            // print hex - using the hex number as the array index of ColorArray to retrieve a color
            try stdout.print("{s}{x:0>2}{s}", .{ clr, line[i], CLR });


Hey @hexxy, welcome to Ziggit :slight_smile:

I just want to chime in real quick to make you aware that you’re returning pointers to temporary memory: Pointers to Temporary Memory

var array: [256][]const u8 = undefined;
...
return &array;

So, be careful about that. You can’t return a pointer or reference to var types from comptime to the outside world. In a comptime context, you’ll need to freeze its state by assigning it to a const value first (remember, this only applies in a comptime context - this is still a problem if you’re in a runtime context):

comptime {
    var something: [42]T = undefined;
    // fill/modify something...
    const freeze = something;
    return freeze[0..];
}

I’d have to restructure your program to try this, but here’s an idea - if you’re not going to change the array during runtime, you can compute it in place and make it const:

const array: [256][]const u8 = blk: {
     var tmp: [256][]const u8 = undefined;
     // do stuff to tmp...
     break :blk tmp; // copy by value into const array...
};

If you can rephrase your problem in those terms, that’s probably the best way to go. Looks stable too - I’m getting anonymous string literals in the assembly output so it seems like returning an array to constant slices is durable:

__anon_1311:
        .asciz  "abc"
4 Likes

Thanks for the guidance! :slight_smile: I think that puts me on the right track. Comptime is a really interesting concept, I’ll have to mess around with it some more.

Edit: Yep, that did it! Super cool.

3 Likes