[Solved] C header function translated to ZIG makes errors

Hello all,

currently I’m working on a simple ZIG bootloader for a custom kernel (it will become open-source after the first time it’s working) and I am using a GitHub Repository as idea. After the last question AndrewCodeDev said “Keep us posted” and I have just one question after the other :smiley:
So, in src/bootloader/src/loader.c line 40 I found the (GNU EFI) #define function EFI_SIZE_TO_PAGES, which led me to a quick code search.
I discovered this function at inc/efidef.h line 208 and just used zig translate-c.
After a bit clean-up, it looked like the following:

pub const efi_page_mask: usize = 0xfff;
pub const efi_page_shift: usize = 12;

pub inline fn efiSizeToPages(value: anytype) @TypeOf(value) {
    return (value >> efi_page_shift) + (if (value & efi_page_mask) 1 else 0);
}

But now, when I call it with an usize as argument, the build fails with:

src/bootloader/efi_additional.zig:5:51: error: expected type 'bool', found 'usize'
    return (value >> efi_page_shift) + (if (value & efi_page_mask) 1 else 0);
                                            ~~~~~~^~~~~~~~~~~~~~~

How should I understand this error?
Has anyone any idea how to fix this?

Looking forwards,
Samuel Fiedler

In C that bitmask & operation is automatically converted to a boolean value – 0 is considered false, non-0 is true. You just have to make this conversion explicit:

if ((value & efi_page_mask) > 0) 1 else 0

(and maybe you don’t need all those parenthesis in there).

Then it greets me with:

src/bootloader/efi_additional.zig:5:41: error: value with comptime-only type 'comptime_int' depends on runtime control flow
    return (value >> efi_page_shift) + (if ((value & efi_page_mask) > 0) 1 else 0);
                                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/bootloader/efi_additional.zig:5:69: note: runtime control flow here
    return (value >> efi_page_shift) + (if ((value & efi_page_mask) > 0) 1 else 0);
                                            ~~~~~~~~~~~~~~~~~~~~~~~~^~~

This compiles fine for me with zig version 0.11.0:

const efi_page_mask: usize = 0xfff;
const efi_page_shift: usize = 12;
pub inline fn efiSizeToPages(value: anytype) @TypeOf(value) {
    const ret = (value >> efi_page_shift) + (if (value & efi_page_mask > 0) 1 else 0);
    return ret;
}

For me this also compiles fine. But if I call it like the following:

pub fn doSomething(oneArgument: usize) usize {
    return efiSizeToPages(oneArgument);
}

Then it makes errors if the “oneArgument” is not compile-time-known.

Here’s one fix:

pub inline fn efiSizeToPages(value: anytype) @TypeOf(value) {
    const addition: @TypeOf(value) = if (value & efi_page_mask != 0) 1 else 0;
    const ret = (value >> efi_page_shift) + addition;
    return ret;
}

I believe the problem is that both 1 and 0 are of type comptime_int, so it’s trying to evaluate the if condition at comptime since it thinks the result type of the if expression is comptime_int.

Another way to resolve it would be to use @as to give the 1 / 0 a type other than comptime_int (e.g. @as(@TypeOf(value), 1))

1 Like

I thought casting to from bool back to type(value) would work, but that also failed weirdly:

pub fn ef(value: anytype) @TypeOf(value) {
    return (value >> efi_page_shift) + @as(@TypeOf(value), (value & efi_page_mask) != 0);
}

returned

./example.zig:8:84: error: expected type 'usize', found 'bool'
    return (value >> efi_page_shift) + @as(@TypeOf(value), (value & efi_page_mask) != 0);
                                                                                ^

but @bitCast(u1, @as(bool(...)) compiled though

I think you can use @intFromBool there.

This worked for me, thanks!

What is the diference between that and @as?

Actually it would replace the @bitCast, not the @as. So you go from

@bitCast(u1, @as(bool(…))

to

@intFromBool(@as(bool, ....

I think technically this is the same thing but it reads like a more direct expression of your intent in my opinion.

difference between int from bool and as?

@as doesn’t do conversion between bool and integer types. @as is intended to be always safe, no matter what, and I guess treating a bool as an integer doesn’t qualify as such.