4 ms·
The correct answer to this is actually "syntax error" because your `0xFFOO:15` has got two letter O's in it and anyway 0xFF00 isn't valid erlang (no hex literal
by rkangel 4y ago
The correct answer to this is actually "syntax error" because your `0xFFOO:15` has got two letter O's in it and anyway 0xFF00 isn't valid erlang (no hex literals).
If you mean this equivalent bit of Elixir, then I got it right:
<<1::5, 2::4, 0xFFOO::15, "foo"::binary>>
I think it's all good and sensible, except that "0xFF00::15" should raise an error. The bit syntax silently masks out some stuff which can hide some errors.
- throwawaymaths 4y agoYeah, sorry typing on phone. Ok. Maybe I'm just dumb. But I was really surprised that the bit order goes from msbit to lsbit (while the byte order goes from lsbyte to msbyte). Since the 15 bit element crosses over the byte boundary (and overflows it) the arrangement -- 00s in byte 1 and 0x80 0x3F in bytes 2 and 3... is not obvious, to me). In particular this makes it tricky to reinterpret packed structs coming from c, when using NIFs Specifically, what I would have wanted, was lsb-msb in bytes, and an overflow error, or syntax in the descriptor modifier that is required if you might overflow. Or, this would all be solved if we used an RTL layouts like the divine one intended.
- rkangel 4y agoThe important thing to remember, it's just a sequence of bits (and if that's a multiple of 8 then you can look at it as a sequence of bytes instead). Byte boundaries are just a way of looking at the result. You get the bits in the order you ask for in the expression, and then it encodes each valuee as you ask. Note that the default encoding is big endian, so the value 0xFF00 comes out as the bit sequence 1111111100000000 wherever it is. Now converting from a C-struct you absolutely do have to think about byte order, but erlang has you there too. Let's say you've got this: #pragma pack(1) struct { uint16_t a; uint8_t b; uint8_t c; uint32_t d; }; Then all you do is: <<a::16-native, b::8, c::8, d::32-native>> = my_block_of_data And then all of your values (a, b, c, d) will be correct. As I said above, erlang defaults to encoding/decoding each value as big-endian (e.g. <<0xFF00::16>> is equivalent to <<0xFF00::16-big>>. This is the default because big endian is used for the vast majority of comms protocols (in that context it's also called 'network byte order'). When interpreting values in memory though it can be either, depending on your processor (although mostly -little these days). Using -native as yoru endianness means "use big or little as appropriate for my processor". It's also a good signal that you're interpreting something from memory (as supposed to a protocol).
- throwawaymaths 4y agoI'm not talking about byte-sized data though. It's bit-sized, that's tough, especially when it crosses byte boundaries.