upvote
> Just don't allow casting to u24, as it makes no sense unless you define u24 to be u32 sized as I think c standard does.

The reason u32->u24 casting must be well defined is because some hardware (e.g. many GPUs, microcontrollers) only have floating point multipliers. A 24 bit unsigned integer (stored in a 32 bit register) can be losslessly converted to a 32 bit float by the hardware, multiplied, then converted back.

This is much faster than doing 32 bit multiplication in software, however, you still need to tell the compiler about this constraint.

reply
I am criticizing the part where they allowed [3]u8 to u24 bitCast in the first place. It doesn't make sense logically as u24 is likely not 24 bits in any targets let alone portably on every target.

Interpreting u24 like it is actually 24 bits sounds like programming in crazy land since it is not 24 bits in any relevant architecture afaik

reply
> many GPUs

Citation please - every single GPU in the literal world supports integer arithmetic for operating on tid, gid, etc.

reply
GCC has had __int24 for the AVR backend for some time. Useful for larger integers than int16_t while saving 25% over a 32-bit value. C23 does not mandate padding for _BitInt types. It is wrong to assume that will happen or is the optimal implementation for portable code.
reply
Thanks for the context, but what I am criticising is this part:

> it became allowed to use @bitCast to reinterpret a [3]u8 as a u24

This cant't make sense unless u24 is defined to be 24bits in the first place. It is just silly to allow something like this. It would make so much more sense to me if they started disallowing this or just even print a deprecation notice for it for one release version.

> Useful for larger integers than int16_t while saving 25% over a 32-bit value

You can't even do []u24 in zig as far as I can remember and understand anyway so this is only happening in a packed struct context.

C doesn't mandate padding but C compilers allow having pointers and arrays of irregular _BitInt types as far as I can understand.

In this [1] document, in Abi considerations section, it writes that it is defined to have next-power-of-two layout size.

Also here (for RISCV) [2] it seems like it is defined with next-power-of-two layout.

Also the document here (for x86_64) defines it similarly [3]

[1] https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2709.pdf

[2] https://github.com/riscv-non-isa/riscv-elf-psabi-doc/issues/...

[3] https://gitlab.com/x86-psABIs/x86-64-ABI/-/tree/master?ref_t...

reply
If I understand it correctly, it basically boils down to copying bits from the source to the destination, in order from the least significant bit to the most significant bit. It's not equivalent to C++'s reinterpret_cast.

I'm no Zig expert, but if you want endian-dependent semantics I'd assume either @ptrCast or a packed union would do the job.

reply
But doesn't that show why this is a bad idea? If I understand correctly, this code:

  const MyUnion = packed union {
    full: u16,
    bytes: [2]u8,
  };
  const value: u16 = 0x55aa;
  const in_union: MyUnion = @bitCast(value);
  const without_union: [2]u8 = @bitCast(value);
  std.debug.assert(without_union[0] == in_union.bytes[0]);
  std.debug.assert(without_union[1] == in_union.bytes[1]);
...will now succeed or fail depending on the endianness of the target. That looks like the type of footgun that will bring decades of joy.
reply
zig does not allow arrays in packed structs/unions specifically for endianness reasons (there may be other reasons as well but endianness is what i know of)
reply
I wonder if packed union also got/will get the same "logical bits" treatment?
reply
My understanding is that the "logical bits" view breaks down for unions, because the nth logical bit could be at different offsets depending on the union variant that's considered active.
reply
> This is a huge mistake. You would never expect something like bitCast to do this.

Is there at least some sort of @transmute or something ? If Zig wants to say "bitCast" means this odd operation, but provides the thing most people actually want under some plausible name that's just an extra thing to learn which seems OK.

reply
You don't need to use @bitCast for the behavior you're talking about. @ptrCast still exists.
reply
@ptrCast,

> Converts a pointer of one type to a pointer of another type. [1]

[1] https://ziglang.org/documentation/master/#toc-ptrCast

So it is not the same.

You could use it to define a function that implements bitCast. Which defeats the purpose of having any @bitCast intrinsic instead of using @mempcy for everything

reply
Take the address and deref afterwards, and it's exactly the same. Or to say another way: if you want bits to be reinterpreted raw as if they're in memory, then... put them in memory, then reinterpret them.

> You could use it to define a function that implements bitCast. Which defeats the purpose of having any @bitCast intrinsic

Yes, and this is one reason @bitCast was changed to have semantics that are not trivially achieved with @ptrCast.

reply
To me it makes sense. If you don't know what endianness is, it doesn't make sense that a program you write in one programming language works for one target but doesn't work for the other.

I think endianness is the footgun that Zig is solving, rather than Zig being the one introducing a footgun when you deal with endianness.

reply
> If you don't know what endianness is

It is not feasible for someone to write endian portable code in a language like Zig without understanding what endianness is imo. Regardless of how they change @bitCast there will be other cases that break this like doing @ptrCast + @memcpy.

Also this breaks currently written code that is endian portable and uses @byteSwap like it is done in most other programming languages that do these things.

reply
deleted
reply