Hi forum,
I’m having trouble to figure out how to go from the bit_set to the c.ulong needed for the C API function I need to call.
Here is my naive attempt in a self-contained file:
package test_bit_set
import "core:c"
import "core:fmt"
PortFlag :: enum c.int {
// Docs: https://jackaudio.org/api/types_8h.html#acbcada380e9dfdd5bff1296e7156f478
IsInput = 1,
IsOutput = 2,
IsPhysical = 4,
CanMonitor = 8,
IsTerminal = 16,
}
PortFlags :: distinct bit_set[PortFlag;c.int]
main :: proc() {
input_flags: PortFlags = {PortFlag.IsInput}
output_flags: PortFlags = {PortFlag.IsOutput, PortFlag.IsPhysical}
output_flags_ulong: c.ulong = c.ulong(output_flags) // <- how to do this??
fmt.println("Output flags ulong", output_flags_ulong)
}
If I try to build/run this with odin run port_flags.odin -file I get the error:
port_flags.odin(21:40) Error: Cannot cast 'output_flags' as 'u64' from 'PortFlags'
output_flags_ulong: c.ulong = c.ulong(output_flags)
^~~~~~~~~~~^
How can I do this?
Thanks in advance!
Oh!! I can just loop over the bit_set !
main :: proc() {
input_flags: PortFlags = {PortFlag.IsInput}
output_flags: PortFlags = {PortFlag.IsOutput, PortFlag.IsPhysical}
output_flags_ulong: c.ulong
for c in output_flags {
fmt.println("element is set", c)
output_flags_ulong += u64(c)
}
fmt.println("output_flags_ulong", output_flags_ulong)
}
That was much simpler than what I thought!
Anyway, let me know if there is a better way of doing this =)
transmute is what you want, not a cast. Transmutation is a bit-for-bit conversion, whereas cast will attempt to do type conversion if possible.
You transmute the bit_set to its underlying type (c.int in this case), then cast that to c.ulong.
2 Likes
Hello @Feoramund – thanks for the answer!
That sounds more elegant indeed.
However, when I try the transmute approach I get a weird value 20 instead of the 6 (2 + 4) that I was expecting.
Full program:
package test_bit_set
import "core:c"
import "core:fmt"
PortFlag :: enum c.int {
// Docs: https://jackaudio.org/api/types_8h.html#acbcada380e9dfdd5bff1296e7156f478
IsInput = 1,
IsOutput = 2,
IsPhysical = 4,
CanMonitor = 8,
IsTerminal = 16,
}
PortFlags :: distinct bit_set[PortFlag;c.int]
main :: proc() {
input_flags: PortFlags = {PortFlag.IsInput}
output_flags: PortFlags = {PortFlag.IsOutput, PortFlag.IsPhysical}
output_flags_ulong: c.ulong
for c in output_flags {
fmt.println("element is set", c)
output_flags_ulong += u64(c)
}
fmt.println("output_flags_ulong with for-loop", output_flags_ulong)
output_flags_ulong = c.ulong(transmute(c.int)output_flags)
fmt.println("output_flags_ulong with transmute", output_flags_ulong)
}
The above prints the correct value for the for-loop, but a funny value for one calculated with transmute:
element is set IsOutput
element is set IsPhysical
output_flags_ulong with for-loop 6
output_flags_ulong with transmute 20
Any idea on what am I missing?
Right, so in this instance, you wouldn’t set the values of PortFlag, as a bit_set uses the value of the enum as a bit index rather than a value to be OR’d. If you remove the = [powers of two] assignments from the enum, the transmute results in 6 as expected.
2 Likes
Ohhh, that makes sense, thank you!
Right, so my enum type won’t match the values as in the C API.
That might be okay, I just need to double check if it makes sense for my case.
Thank you for your help, have a good day!
No, that enum type won’t match the C API values.
You can either use the bit_set as an interface where you transmute to and from that type when inter-operating with C, or you can have both a bit_set that refers to one enum where the values are all contiguous integers that refer to bit indexes, then you have a separate enum for the exact value that can be used with individual bit operations.
2 Likes
Right!
From a quick check, it seems that the flags are never used alone, so I think I’ll keep the bit_set without them.
If someday I truly need them, I guess I can just do 1 << PortFlag.IsOutput or something.
Thanks again!
1 Like
nesh
30 July 2025 05:33
9
1 Like